//*********************************************************
//
//    Copyright (c) Microsoft. All rights reserved.
//    This code is licensed under the Apache License, Version 2.0.
//    THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
//    ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
//    IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
//    PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
//
//*********************************************************

using Microsoft.Research.ScientificWorkflow;
namespace Microsoft.Research.ScientificWorkflow.TridentComposer
{
    #region Using Directives

    using System;
    using System.Collections;
    using System.Collections.Generic;
    using System.Collections.ObjectModel;
    using System.ComponentModel;
    using System.ComponentModel.Design;
    using System.ComponentModel.Design.Serialization;
    using System.Globalization;
    using System.IO;
    using System.Linq;
    using System.Net;
    using System.Reflection;
    using System.Text;
    using System.Workflow.ComponentModel.Compiler;
    using System.Workflow.ComponentModel.Serialization;
    using System.Xml;
    using Microsoft.Research.ScientificWorkflow.TridentModel;
    using Microsoft.Research.ScientificWorkflow.TridentUtilities;
    using Microsoft.Practices.EnterpriseLibrary.Logging;
    using Microsoft.Research.DataLayer;
    using TridentAPI;
    using ER = Microsoft.Research.DataLayer;
    using WFActivity = System.Workflow.ComponentModel.Activity;
    using WFCompModel = System.Workflow.ComponentModel;

    #endregion

    /// <summary>
    /// Workflow composer class.
    /// </summary>
    public class WorkflowComposer : IDisposable
    {
        #region Private Member Data

        /// <summary>
        /// Input string.
        /// </summary>
        private static string input = "Input";

        /// <summary>
        /// Output string.
        /// </summary>
        private static string output = "Output";

        /// <summary>
        /// The directory name for the temp directory that acts as the holding directory for downloads.
        /// </summary>
        private static string TridentTempDirPath = "TridentTemp";

        /// <summary>
        /// This is the store for all the assemblies the workflow is using.
        /// </summary>
        private TypeProvider typeProvider;

        /// <summary>
        /// This Container holds the service for the typeprovider.
        /// </summary>
        private ServiceContainer serviceContainer;

        /// <summary>
        /// This holds connection to the registry.
        /// </summary>
        private Connection registryConnection;

        /// <summary>
        /// Activity composer object.
        /// </summary>
        private ActivityComposer actComposer;

        /// <summary>
        /// Contains the activities which are update to the registry.
        /// </summary>
        private Dictionary<string, Activity> updatedActivities = new Dictionary<string, Activity>();

        /// <summary>
        /// The model factory.
        /// </summary>
        private ModelFactory modelFactory;

        #endregion

        #region Constructors
        /// <summary>
        /// This instantiates the registry Connection and 
        /// loads the Default Assemblies.
        /// </summary>
        /// <param workflowName="registryConnection">Registry Connection.</param>
        public WorkflowComposer(
            Connection registryConnection,
            ActivityComposer activityComposer)
            : this(registryConnection, null, activityComposer)
        {

        }

        /// <summary>
        /// This instantiates the Loader Class with Registry Connection and the TypeProvider.
        /// </summary>
        /// <param workflowName="connection">Registry Connection.</param>
        /// <param workflowName="provider">Type Provider which has the AAssemblies loaded.</param>
        public WorkflowComposer(
            Connection connection,
            TypeProvider provider,
            ActivityComposer activityComposer)
        {
            #region Validation
            if (null == connection)
            {
                throw new ArgumentNullException("connection");
            }
            if (null == activityComposer)
            {
                throw new ArgumentNullException("activityComposer");
            }
            #endregion

            // For loading the workflowcommon into the appdomain.
            System.Type tp = typeof(global::Microsoft.Research.ScientificWorkflow.NameAttribute);
            string typename = tp.Name;
            tp = null;

            // For Loading SequentialWorkflowActivity into app domain
            tp = typeof(global::System.Workflow.Activities.SequentialWorkflowActivity);
            typename = tp.Name;
            tp = null;

            // For Loading TridentAPI into app domain
            tp = typeof(global::TridentAPI.BaseTypeInitializer);
            typename = tp.Name;
            tp = null;

            // Sets the Type Provider
            this.typeProvider = provider;

            // Sets the registry Connection.
            this.registryConnection = connection;

            this.serviceContainer = new ServiceContainer();

            // If actType provider is null then it loads the Default Trident Assemblies.
            if (this.typeProvider == null)
            {
                this.typeProvider = new TypeProvider(serviceContainer);
            }

            // Adds the TypeProvider Service to the Service Container.
            this.serviceContainer.AddService(typeof(ITypeProvider), this.typeProvider);

            this.actComposer = activityComposer;
            this.modelFactory = new ModelFactory(this.actComposer.ActivityMetadataList, this.actComposer.SupportedActivityCollection);
        }

        #endregion

        #region Public properties

        /// <summary>
        /// Gets the activity composer.
        /// </summary>
        public ActivityComposer ActComposer
        {
            get
            {
                return actComposer;
            }
        }

        /// <summary>
        /// Gets the path of the temporary directory.
        /// </summary>
        public static string TempDirPath
        {
            get
            {
                return WorkflowComposer.TridentTempDirPath;
            }
        }

        /// <summary>
        /// Gets or sets the directory of the imported workflow.
        /// </summary>
        public static DirectoryInfo TempImportedWorkflowDirectory
        {
            get;
            private set;
        }
        #endregion

        #region Public Methods

        /// <summary>
        /// Crete a temporary directory to store the downloaded libraries.
        /// </summary>
        /// <returns>The temp directory location.</returns>
        public static string CreateTempDirectory()
        {
            string dllDirectoryPath = string.Empty;
            try
            {
                if (!string.IsNullOrEmpty(WorkflowUtilities.TempDirPath))
                {
                    dllDirectoryPath = Path.Combine(
                        Path.Combine(WorkflowUtilities.TempDirPath, WorkflowComposer.TridentTempDirPath),
                        Guid.NewGuid().ToString("N"));
                }
                else
                {
                    dllDirectoryPath = Path.Combine(
                     Path.Combine(Path.GetTempPath(), WorkflowComposer.TridentTempDirPath),
                     Guid.NewGuid().ToString("N"));
                }

                Directory.CreateDirectory(dllDirectoryPath);
            }
            catch (IOException)
            {
                TridentErrorHandler.ThrowTridentCustomException(TridentErrorConstants.ErrorNumber4000037,
                    TridentResourceManager.GetString("TempDirectoryCreationFailed"));
            }
            catch (UnauthorizedAccessException)
            {
                TridentErrorHandler.ThrowTridentCustomException(TridentErrorConstants.ErrorNumber4000037,
                    TridentResourceManager.GetString("TempDirectoryCreationFailed"));
            }
            return dllDirectoryPath;
        }

        /// <summary>
        /// Imports a workflow into the registry.
        /// </summary>
        /// <param name="references">The file references.</param>
        /// <param name="properties">The workflow details.</param>
        /// <param name="userName">The creator of the workflow.</param>
        /// <param name="updateOnlyWorkflow">A flag to specify whether activities should be imported or not.</param>
        /// <returns>True if import succeeds; False otherwise.</returns>
        public Guid ImportWorkflow(
          Collection<FileReference> references,
          WorkflowProperties properties,
          string userName,
          bool updateOnlyWorkflow)
        {
            // Clear the updated activities before starting new import.
            updatedActivities.Clear();

            WFActivity loadedWorkflow = this.CreateWFActivity(references);

            bool succeeded = true;

            if (!updateOnlyWorkflow)
            {
                ImportActivity importActivityHelper = new ImportActivity(this.registryConnection, false);
                succeeded = importActivityHelper.ImportActivities(references, this.updatedActivities, false);
                ImportTypeInitializer(references, this.registryConnection);
            }

            Activity importedActivity = null;
            if (succeeded)
            {
                importedActivity = this.CreateWorkflowInRegistry(loadedWorkflow, properties, userName, updateOnlyWorkflow, references);
            }

            updatedActivities.Clear();
            return importedActivity == null ? Guid.Empty : (importedActivity as IObject).ID;
        }

        /// <summary>
        /// Imports Type initializers from the Colloection of File references.
        /// This fucntion will check if there are any assembly which conatins TypeInitializers and then imports if present.
        /// </summary>
        /// <param name="references">FileRefernces Collection.</param>
        public static void ImportTypeInitializer(Collection<FileReference> references, Connection registryConnection)
        {

            IEnumerable<FileReference> customTypes = references.Where(fileRef => WorkflowComposer.ContainsCustomType(fileRef.FilePath));
            foreach (FileReference fileRef in customTypes)
            {
                ImportTypeInitializerProxy importTypeInitializer = new ImportTypeInitializerProxy(fileRef.FilePath, registryConnection);
                importTypeInitializer.Execute();
                TypeProviderHelper.RefreshTypeInitializersCache();
            }
        }

        /// <summary>
        /// Build a workflow model from the Id passed.
        /// </summary>
        /// <param name="workflowId">WOrkflow guid.</param>
        /// <param name="isWorkflowDrop">A flag to determine if this is a workflow drag drop scenario. 
        /// This is needed to determine wheter the blackboard xoml is to be deserialized or not.</param>
        /// <returns>Workflow model.</returns>
        public TridentWorkflowModel GetWorkflowModel(Guid workflowId, bool isWorkflowDrop)
        {
            #region Validation of Arguments
            if (workflowId == null || workflowId.Equals(Guid.Empty))
            {
                throw new ArgumentNullException("workflowId");
            }
            #endregion

            TridentWorkflowModel tridentWorkflowModel = null;
            if (this.registryConnection != null && this.registryConnection.Alive)
            {
                Activity erActivity = null;
                try
                {
                    erActivity = Activity.Load(workflowId, this.registryConnection);

                    // Create a workflow model out of the eractivity got from the registry.
                    tridentWorkflowModel = new TridentWorkflowModel(erActivity, this.modelFactory);
                    // Check if newer versions exist for the workflow.
                    if (!erActivity.IsLatestVersion())
                    {
                        tridentWorkflowModel.NewerVersionsExist = true;
                    }

                    if (isWorkflowDrop && erActivity.IsBlackbox)
                    {
                        tridentWorkflowModel.BlackBoxActivity = this.LoadBlackboxWorkflow(erActivity);
                    }
                }
                catch (RecordNotFoundException ex)
                {
                    TridentErrorHandler.HandleAndThrowBusinessLogicException(
                        ex,
                        TridentErrorConstants.ErrorNumber6000002,
                        TridentResourceManager.GetString("WorkflowNotFound"));
                }
                catch (Exception exp)
                {
                    TridentErrorHandler.HandleAndThrowBusinessLogicException(
                     exp,
                     TridentErrorConstants.ErrorNumber6000002,
                     exp.Message);
                }
            }
            else
            {
                TridentErrorHandler.ThrowTridentCustomException(
                    TridentErrorConstants.ErrorNumber6000003,
                    TridentResourceManager.GetString("NoRegistryFound"));
            }

            return tridentWorkflowModel;
        }

        /// <summary>
        /// Read all the workflow categories from the registry and 
        /// return a list of workflow category models.
        /// </summary>
        /// <returns>Workflow category model list.</returns>
        public Collection<WorkflowCategoryModel> ReadAllWorkflowCategories(User user)
        {
            #region Validation of Arguments
            if (null == user)
            {
                throw new ArgumentNullException("user");
            }
            #endregion

            Collection<WorkflowCategoryModel> systemCategories = null;
            if (this.registryConnection != null && this.registryConnection.Alive)
            {
                systemCategories = CategoriesComposer.ReadSystemWorkflowCategories(this.registryConnection, user.Name);
                Collection<WorkflowCategoryModel> workflowCategoryModels = CategoriesComposer.ReadWorkflowCategoriesForUser(
                this.registryConnection,
                user);

                foreach (WorkflowCategoryModel userCategory in workflowCategoryModels)
                {
                    systemCategories.Add(userCategory);
                }
            }


            return systemCategories;
        }

        /// <summary>
        /// Used to create a new version of the workflow in registry.
        /// </summary>
        /// <param name="workflowModel">workflow model which has to be updated</param>
        /// <param name="fileReferences"></param>
        /// <param name="userName">User name.</param>
        /// <returns>Whether updated or not.</returns>
        public Activity UpdateWorkflowInRegistry(TridentWorkflowModel workflowModel, Collection<FileReference> fileReferences, string userName)
        {
            #region Validation of Arguments
            if (workflowModel == null)
            {
                throw new ArgumentNullException("workflowModel");
            }

            if (Guid.Empty.Equals(workflowModel.Id))
            {
                TridentErrorHandler.ThrowTridentCustomException(
                   TridentErrorConstants.ErrorNumber6000019,
                   TridentResourceManager.GetString("InvalidWorkflowID"));
            }

            if (string.IsNullOrEmpty(userName))
            {
                throw new ArgumentNullException("userName");
            }


            #endregion

            Activity registryActivity = null;
            ActivitySequence baseSequence = null;
            Dictionary<string, ActivitySequence> nameToSequenceMap = null;

            // Create a new version of the workflow.
            registryActivity = this.SaveERActivity(workflowModel);

            // Update Activity Sequence in registry.
            baseSequence = this.CreateActivitySequence(
                workflowModel,
                registryActivity,
                fileReferences,
                ref nameToSequenceMap,
                false);

            baseSequence.Refresh();

            // Update Parameters in registry.
            #region Update Parameters
            string updateParamError = string.Empty;
            updateParamError = this.UpdateParameters(workflowModel.Root, nameToSequenceMap);

            // Throw Exception if there is any error while updating the parameters.
            if (!string.IsNullOrEmpty(updateParamError))
            {
                StringBuilder errorStr = new StringBuilder();

                errorStr.AppendLine(TridentResourceManager.GetString("PropertyUpdateFailed"));
                errorStr.AppendLine(updateParamError);

                TridentErrorHandler.ThrowTridentCustomException(
                    TridentErrorConstants.ErrorNumber6000009,
                    errorStr.ToString());
            }
            #endregion

            this.AssignPackagesForProperties(workflowModel, registryActivity, fileReferences);

            workflowModel.SavedIsInteractiveValue = workflowModel.IsInteractive;

            // Set the category of the workflow.
            this.SetNamespace(registryActivity, workflowModel.Category.Id, userName);

            return registryActivity;
        }

        /// <summary>
        /// Save the new workflow into the registry.
        /// </summary>
        /// <param name="newWFModel">Workflowmodel of the workflow which has to be created.</param>
        /// <param name="userName">User name.</param>
        /// <returns>Whether saved or not.</returns>
        public bool SaveWorkflowInRegistry(
            TridentWorkflowModel newWFModel,
            Collection<FileReference> openedReferences,
            string userName)
        {
            #region Validation of Arguments
            if (newWFModel == null)
            {
                throw new ArgumentNullException("newWFModel");
            }

            if (string.IsNullOrEmpty(userName))
            {
                throw new ArgumentNullException("userName");
            }
            #endregion

            Activity savedActivity = null;
            savedActivity = this.CreateWorkflow(newWFModel, openedReferences, userName, false);

            WorkflowMetadata meta = new WorkflowMetadata(savedActivity);
            newWFModel.Category.Workflows.Add(meta);

            newWFModel.Id = ((IObject)savedActivity).ID;
            newWFModel.SavedIsInteractiveValue = savedActivity.IsInteractive;
            newWFModel.IsLoadedFromRegistry = true;
            newWFModel.VersionLabel = string.Empty;
            return true;
        }

        /// <summary>
        /// This function is used to save the workflow which was opened from file system to registry.
        /// </summary>
        /// <param name="workflowName">Name of the workflow.</param>
        /// <param name="description">Description of the workflow.</param>
        /// <param name="categories">Categories of the workflow.</param>
        /// <param name="newWFModel">Workflowmodel of the workflow which has to be created.</param>
        /// <returns>New workflow model.</returns>
        public TridentWorkflowModel SaveWorkflowFromFileSystemInRegistry(
            string workflowName,
            TridentWorkflowModel newWFModel,
            Collection<FileReference> openedReferences,
            string userName)
        {
            /// Logic: 
            ///      Download the Libraries.
            ///      Generate the component model activity.
            ///            (This is required overe here because we need to create the activities which are not present in the library.)
            ///      Then save the newly created component model activity into the registry.

            #region Validation of Arguments
            if (string.IsNullOrEmpty(workflowName))
            {
                throw new ArgumentNullException("workflowName");
            }

            if (newWFModel == null)
            {
                throw new ArgumentNullException("newWFModel");
            }
            #endregion

            // Clear the updated activities before starting new import.
            ClearUpdateStatus();

            TridentWorkflowModel savedModel = null;
            try
            {
                // Import all activities.
                ImportActivity importActivity = new ImportActivity(this.registryConnection, false);
                bool succeeded = importActivity.ImportActivities(openedReferences, updatedActivities, false);

                if (succeeded)
                {
                    ImportTypeInitializer(openedReferences, this.registryConnection);
                    FileReference workflowFile = openedReferences.FirstOrDefault(f => Helper.IsWorkflowFile(f.FilePath));

                    // If update existing is selected set the Id of the workflow model. 
                    // This will make the "CreateWorkflow" method create a newer version of the selected workflow.
                    if (workflowFile.UpdateExisting)
                    {
                        newWFModel.Id = workflowFile.AssemblyInRegistryToUpdate.Id;
                    }

                    // Create workflow in registry.
                    Activity savedActivity = this.CreateWorkflow(newWFModel, openedReferences, userName, true);

                    // Add workflow details to the category model so that the left pane is updated.
                    WorkflowMetadata meta = new WorkflowMetadata(savedActivity);
                    newWFModel.Category.Workflows.Add(meta);
                    newWFModel.Id = ((IObject)savedActivity).ID;

                    if (savedActivity != null && this.modelFactory != null)
                    {
                        // Create the Workflow model form the Registry Activity.
                        savedModel = new TridentWorkflowModel(savedActivity, this.modelFactory);
                    }
                }
            }
            catch (TridentCustomException)
            {
                throw;
            }
            catch (Exception exception)
            {
                TridentErrorHandler.HandleAndThrowBusinessLogicException(exception, TridentErrorConstants.ErrorNumber4000070, exception.Message);
            }
            return savedModel;
        }

        /// <summary>
        /// This function is used save the workflow into the XML writter passed in.
        /// </summary>
        /// <param name="newWFModel">Workflow Model.</param>
        /// <param name="fileName">The file path of the xoml.</param>
        /// <param name="tempDirectory">The temp directory to which the files are to be downloaded.</param>
        /// <exception cref="">WorkflowValidationFailedException</exception>
        public void SaveWorkflow(TridentWorkflowModel newWorkflowModel, string fileName, string tempDirectory)
        {
            #region Validation of Arguments
            if (newWorkflowModel == null)
            {
                throw new ArgumentNullException("newWorkflowModel");
            }

            if (string.IsNullOrEmpty("fileName"))
            {
                throw new ArgumentNullException("fileName");
            }
            #endregion

            try
            {
                WFActivity toSaveWF;

                // Get the file for which the XOML contents has to be saved.
                using (XmlTextWriter writer = new XmlTextWriter(fileName, Encoding.ASCII))
                {
                    // Get the ComponentModel Activity.
                    toSaveWF = this.GetComponentModelActivity(newWorkflowModel, true, tempDirectory);

                    // Save the workflow into the File specified by User.
                    this.SaveWorkflow(writer, toSaveWF);
                }
            }
            catch (TridentCustomException)
            {
                throw;
            }
            catch (Exception ex)
            {
                TridentErrorHandler.ThrowTridentCustomException(TridentErrorConstants.ErrorNumber4000079, ex.Message);
            }
        }

        /// <summary>
        /// Soft Deletes the workflow in the registry
        /// </summary>
        /// <param name="id">Guid</param>
        public void DeleteWorkflowInRegistry(Guid id)
        {
            #region Validation of Arguments
            if (id == null)
            {
                throw new ArgumentNullException("id");
            }

            if (Guid.Empty.Equals(id))
            {
                TridentErrorHandler.ThrowTridentCustomException(
                   TridentErrorConstants.ErrorNumber6000019,
                   TridentResourceManager.GetString("InvalidWorkflowID"));
            }
            #endregion

            Activity workflowToDelete = null;
            try
            {
                workflowToDelete = Activity.Load(id, registryConnection);

                if (workflowToDelete != null)
                {
                    WorkflowComposer.DeleteWorkflow(workflowToDelete);
                }
            }
            catch (Exception exp)
            {
                TridentErrorHandler.HandleAndThrowBusinessLogicException(
                       exp,
                       TridentErrorConstants.ErrorNumber4000036,
                       exp.Message);
            }
        }

        /// <summary>
        /// Delete the workflow. Deletes the older versions as well as their schedules.
        /// </summary>
        /// <param name="workflowToDelete">The workflow to delete.</param>
        public static void DeleteWorkflow(Activity workflowToDelete)
        {
            if (workflowToDelete == null)
            {
                throw new ArgumentNullException("workflowToDelete");
            }
            try
            {
                // Get all older versions of the workflow.
                Collection<Activity> versionCollection = new Collection<Activity>();
                versionCollection.Add(workflowToDelete);
                workflowToDelete.GetVersionsToDelete(versionCollection);

                // Delete schedules for all the older versions.
                foreach (Activity workflow in versionCollection)
                {
                    WorkflowComposer.DeleteSchedulesOfWorkflow(workflow);

                    workflow.IsDeleted = true;

                    workflow.Save();
                }
            }
            catch (Exception ex)
            {
                TridentErrorHandler.HandleAndThrowBusinessLogicException(
                       ex,
                       TridentErrorConstants.ErrorNumber4000036,
                       TridentResourceManager.GetString("DeleteWorkflowError"));
            }
        }

        /// <summary>
        /// Opens the workflow from the filesystem.
        /// </summary>
        /// <param name="references">
        /// The list of files to be loaded.
        /// </param>
        /// <returns>
        /// Workflow Model.
        /// </returns>
        public TridentWorkflowModel OpenWorkflowFromFileSystem(Collection<FileReference> references)
        {
            #region Validations

            if (null == references)
            {
                throw new ArgumentNullException("references");
            }

            #endregion

            TridentWorkflowModel wfModel = null;
            WFActivity activity = null;

            FileReference workflowFile = references.SingleOrDefault(file => Helper.IsWorkflowFile(file.FilePath));
            if (workflowFile != null)
            {
                activity = this.CreateWFActivity(references);
                string xomlName = System.IO.Path.GetFileNameWithoutExtension(workflowFile.FilePath);
                wfModel = new TridentWorkflowModel(
                                activity,
                                this.modelFactory,
                                xomlName,
                                string.Empty,
                                File.ReadAllText(workflowFile.FilePath));
            }

            return wfModel;
        }

        /// <summary>
        /// This is used to get the original ComponentModel.Activty of the 
        /// workflow which was from the saved to regitsry while importing 
        /// the workflow to trident.
        /// </summary>
        /// <param name="workflowAct">ER.Activity.</param>
        /// <returns>ComponentModel.Activty created.</returns>
        public WFActivity GetActualWorkflow(Activity workflowAct)
        {
            #region Validations
            if (workflowAct == null)
            {
                throw new ArgumentNullException("workflowAct");
            }

            if (string.IsNullOrEmpty(workflowAct.XomlContents))
            {
                throw new ArgumentNullException("workflowAct", TridentResourceManager.GetString("XomlContentNotFoundInRegistry"));
            }
            #endregion

            return GetBlackBoxActivity(workflowAct, WorkflowComposer.CreateTempDirectory());
        }

        /// <summary>
        /// Creates the ComponentModel.Activity from the CompositeActivityModel. 
        /// Used when processing blackbox workflows.
        /// </summary>
        /// <param name="actModel">
        /// Activity Model for which the ComponentModel.Activty has to be created.
        /// </param>
        /// <param name="referenceActivity">
        /// The activity to be used as reference when processing blackbox workflows.
        /// </param>
        /// <param name="loadedAssemblyList">
        /// Assemblies which has been loaded.
        /// </param>
        /// <returns>ComponentModel.Activty created.</returns>
        public WFActivity CreateCompModelActivity(
          CompositeActivityModel actModel,
          WFActivity referenceActivity,
          Collection<Assembly> loadedAssemblyList)
        {
            // Load the Assemblies into typeprovider.
            foreach (Assembly assembly in loadedAssemblyList)
            {
                if (!this.typeProvider.ReferencedAssemblies.Contains(assembly))
                {
                    this.typeProvider.AddAssembly(assembly);
                }
            }

            return this.actComposer.CreateCompModelActivity(
                actModel,
                referenceActivity,
                this.serviceContainer,
                loadedAssemblyList);
        }

        /// <summary>
        /// Check if the workflow has been deleted.
        /// </summary>
        /// <param name="workflowId">The id of the workflow to be checked.</param>
        /// <returns>True if the workflow has been deleted. False otherwise.</returns>
        public bool CheckIfWorkflowDeleted(Guid workflowId)
        {
            if (workflowId == Guid.Empty)
            {
                throw new ArgumentNullException("workflowId");
            }
            bool result = false;
            try
            {
                Activity registryActivity = Activity.Load(workflowId, this.registryConnection);
                result = registryActivity.IsDeleted;
            }
            catch (RecordNotFoundException)
            {
                result = true;
            }
            catch (Exception ex)
            {
                TridentErrorHandler.ProcessKnownExceptionsInBusinessLogic(ex);
                result = true;
            }
            return result;
        }

        /// <summary>
        /// Check if the logged in user has author permission on the workflow.
        /// </summary>
        /// <param name="workflowId">The id of the workflow to be checked.</param>
        /// <returns>True if the access is allowed. False otherwise.</returns>
        public bool CheckWorkflowAuthorAccess(Guid workflowId)
        {
            if (workflowId == Guid.Empty)
            {
                throw new ArgumentNullException("workflowId");
            }
            bool result = false;
            try
            {
                Activity registryActivity = Activity.Load(workflowId, this.registryConnection);
                result = registryActivity.Security.Rights.AuthorWorkflow.Check(TridentAuthentication.LoggedInUser);
            }
            catch (RecordNotFoundException)
            {
                result = false;
            }
            catch (Exception ex)
            {
                TridentErrorHandler.ProcessKnownExceptionsInBusinessLogic(ex);
                result = false;
            }
            return result;
        }
        
        /// <summary>
        /// Gets the workflow.
        /// </summary>
        /// <param name="workflowID">The workflow ID.</param>
        /// <returns></returns>
        public Activity GetWorkflow(Guid workflowId)
        {
            Activity workflow = null;
            try
            {
                workflow = Activity.Load(workflowId, this.registryConnection);
            }
            catch (Exception exp)
            {
                TridentErrorHandler.ProcessKnownExceptionsInBusinessLogic(exp);
                TridentErrorHandler.HandleAndThrowBusinessLogicException(
                    exp,
                    TridentErrorConstants.ErrorNumber1000000045,
                    exp.Message);
            }

            return workflow;
        }

        /// <summary>
        /// Exports the workflow.
        /// </summary>
        /// <param name="workflowID">The workflow ID.</param>
        /// <param name="wfModel">Workflow model.</param>
        /// <param name="opcConnection">The opc connection.</param>
        /// <returns></returns>
        public Activity ExportWorkflow(Guid workflowId, TridentWorkflowModel workflowModel, Connection connection)
        {
            Activity workflow = this.GetWorkflow(workflowId);

            if (workflow != null && workflow.IsDeleted)
            {
                TridentErrorHandler.ThrowTridentCustomException(TridentErrorConstants.ErrorNumber4000086,
                        TridentResourceManager.GetString("PackageWorkflowAlreadyDeleted"));
            }

            // Add xoml contents to the workflow.
            string tempFile = Path.GetTempFileName();

            // Save the workflow to a temp file.
            FileSystemOperationsProxy fileSystemOperationProxy = new FileSystemOperationsProxy(this.registryConnection);
            fileSystemOperationProxy.SaveToFile(tempFile, workflowModel);

            try
            {
                // Read the file contents and assign it to XomlContents.
                workflow.XomlContents = File.ReadAllText(tempFile);
                workflow.Save();
            }
            catch (Exception ex)
            {
                TridentErrorHandler.ThrowTridentCustomException(TridentErrorConstants.ErrorNumber4000088, ex.Message);
            }

            try
            {
                // Delete the temp file.
                File.Delete(tempFile);
            }
            catch
            {
                // Temp file could not be deleted.
                // Just catch the exception and proceed.
            }

            // Export the workflow.
            WorkflowComposer.ExportWorkflowToPackage(workflow, this.registryConnection, connection);

            return workflow;
        }

        #endregion

        #region Private Methods

        /// <summary>
        /// This functiin is used to clear the assemblies in the type provider.
        /// </summary>
        private static void ClearTypeProvider(TypeProvider typeProvider)
        {
            ICollection<Assembly> assmblies = typeProvider.ReferencedAssemblies;
            foreach (Assembly assem in assmblies)
            {
                typeProvider.RemoveAssembly(assem);
            }
        }

        /// <summary>
        /// Assign packages for the properties.
        /// </summary>
        /// <param name="wfModel">Name of the Workflow.</param>
        /// <param name="registryActivity">Registry activity.</param>
        private void AssignPackagesForProperties(TridentWorkflowModel wfModel, Activity registryActivity, Collection<FileReference> references)
        {
            try
            {
                // Also consider the scenario Open from Registry -> Save as to file system .
                // Assign assembly packages which are 
                if (wfModel.IsBlackBox)
                {
                    // Save to registry from file system scenario. As we are passing the wfmodel through the appdomain the blackbox activity will be null.
                    if (wfModel.BlackBoxActivity == null && wfModel.Id.Equals(Guid.Empty) && wfModel.PreviousWorkflowId.Equals(Guid.Empty))
                    {
                        // Load the blackbox workflow from the references. 
                        // This is required as we need to retreive the assembly packages for the properties.
                        wfModel.BlackBoxActivity = CreateWFActivity(references);
                    }

                    if (wfModel.BlackBoxActivity != null)
                    {
                        this.AssignAssemblyPackageForProperties(registryActivity, wfModel.BlackBoxActivity, references);
                    }
                    else
                    {
                        // wfModel.Id is used when the user clicks on save to registry.
                        // wfModel.BackupModelId is used when the user clicks on saveAS.
                        Guid workflowID = wfModel.Id;
                        if (workflowID.Equals(Guid.Empty))
                        {
                            workflowID = wfModel.PreviousWorkflowId;
                        }

                        ER.Activity previourWorkflow = ER.Activity.Load(workflowID, this.registryConnection);
                        foreach (ER.AssemblyPackage asmPkg in previourWorkflow.AssemblyPackages)
                        {
                            if (!ActivityComposer.IsAssemblyPackageAvailable(registryActivity.AssemblyPackages, asmPkg))
                            {
                                registryActivity.AssemblyPackages.Add(asmPkg);
                            }
                        }
                    }

                    registryActivity.AssemblyPackages.Refresh();
                }
            }
            catch (Exception exp)
            {
                TridentErrorHandler.ProcessKnownExceptionsInBusinessLogic(exp);
                TridentErrorHandler.HandleAndThrowBusinessLogicException(
                    exp,
                    TridentErrorConstants.ErrorNumber6000031,
                    exp.Message);
            }
        }

        /// <summary>
        /// This is used to generate the activity from the Workflow Model.
        /// This is specifically used when we know that the Activities 
        /// refering by this is actually present in registry.
        /// </summary>
        /// <param name="wfModel">Workflow model for which the Activity has to be created.</param>
        /// <param name="nullifyForCustomType">Nullify custom type values.</param>
        /// <param name="tempDir">The temp directory for the download of assemblies.</param>
        /// <returns>Activity created.</returns>
        private WFCompModel.Activity GetComponentModelActivity(
            TridentWorkflowModel wfModel,
            bool nullifyForCustomType,
            string tempDir)
        {
            WFCompModel.Activity wfActivity;

            if (wfModel.IsBlackBox)
            {
                wfActivity = GetBlackBoxActivity(wfModel, tempDir);
            }
            else
            {
                this.DownloadBinaries(wfModel, tempDir);
                wfActivity = this.CreateComponentModelActivity(
                    wfModel,
                    nullifyForCustomType,
                    tempDir);
            }

            return wfActivity;
        }

        /// <summary>
        /// This is used to get the original ComponentModel.Activty of the 
        /// workflow which was from the saved to regitsry while importing 
        /// the workflow to trident.
        /// </summary>
        /// <param name="wfModel"></param>
        /// <param name="tempDir">The temp directory to download assemblies.</param>
        /// <returns>ComponentModel.Activty created.</returns>
        private WFCompModel.Activity GetBlackBoxActivity(TridentWorkflowModel wfModel, string tempDir)
        {
            WFCompModel.Activity originalActivity = null;
            WFCompModel.Activity saveActivity = null;

            try
            {
                if (wfModel.Id != null && !wfModel.Id.Equals(Guid.Empty))
                {
                    Activity regActivity = Activity.Load(wfModel.Id, this.registryConnection);

                    originalActivity = this.GetBlackBoxActivity(regActivity, tempDir);

                    wfModel.BlackBoxActivity = originalActivity;
                }
                else
                {
                    originalActivity = wfModel.BlackBoxActivity;
                }
            }
            catch (Exception exp)
            {
                TridentErrorHandler.ProcessKnownExceptionsInBusinessLogic(exp);
                TridentErrorHandler.HandleAndThrowBusinessLogicException(
                    exp,
                    TridentErrorConstants.ErrorNumber6000004,
                    exp.Message);
            }

            this.DownloadBinaries(wfModel, tempDir);

            // Load all the assemblies from the DLL Path.
            string errorLoadAssemblies = WorkflowComposer.LoadAssemblies(this.typeProvider, tempDir);

            if (!string.IsNullOrEmpty(errorLoadAssemblies))
            {
                TridentErrorHandler.ThrowTridentCustomException(
                    TridentErrorConstants.ErrorNumber6000004,
                    errorLoadAssemblies.ToString());
            }

            saveActivity = actComposer.CreateCompModelActivity(
                    wfModel.Root as CompositeActivityModel,
                    originalActivity,
                    this.serviceContainer,
                    WorkflowComposer.GetLoadedAssemblyList());

            if (saveActivity != null)
            {
                // Update the Parameters to the activity model.
                actComposer.UpdateParameter(saveActivity, wfModel.Root, true);
            }

            return saveActivity;
        }

        /// <summary>
        /// This is used to get the original ComponentModel.Activty of the 
        /// workflow which was from the saved to regitsry while importing 
        /// the workflow to trident.
        /// </summary>
        /// <param name="workflowAct">ER.Activity.</param>
        /// <param name="tempDir">The temp directory to download assemblies.</param>
        /// <returns>ComponentModel.Activty created.</returns>
        private WFActivity GetBlackBoxActivity(Activity workflowAct, string tempDir)
        {
            // Write the string to a memorystream temporarily so that it can be consumed by the deserializer.
            using (MemoryStream tempStream = new MemoryStream())
            {
                // Write the string to the memory stream.
                using (StreamWriter tempWriter = new StreamWriter(tempStream))
                {
                    tempWriter.Write(workflowAct.XomlContents);
                    tempWriter.Flush();

                    tempStream.Position = 0;

                    // Download the required binaries to the path.
                    WorkflowComposer.DownloadBinaries(workflowAct, tempDir);

                    // Load the assemblies at the temp directory to the type provider.
                    string errors = WorkflowComposer.LoadAssemblies(this.typeProvider, tempDir);

                    if (string.IsNullOrEmpty(errors))
                    {
                        using (XmlReader reader = new XmlTextReader(tempStream))
                        {
                            // Deserialize the workflow.
                            return this.LoadWorkflow(reader);
                        }
                    }
                    else
                    {
                        TridentErrorHandler.ThrowTridentCustomException(TridentErrorConstants.ErrorNumber4000038, errors);
                    }
                }
            }
            return null;
        }

        /// <summary>
        /// This is used to generate the activity from the Workflow Model.
        /// This identifies whether to create the Sequential or State Machine Workflow.
        /// </summary>
        /// <param name="wfModel">Workflow model for which the Activity has to be created.</param>
        /// <returns>Activity created.</returns>
        private WFCompModel.Activity CreateComponentModelActivity(
            TridentWorkflowModel wfModel,
            bool nullifyForCustomType,
            string dllPath)
        {
            #region Validation of Arguments
            if (wfModel == null)
            {
                throw new ArgumentNullException("wfModel");
            }

            if (string.IsNullOrEmpty(dllPath))
            {
                throw new ArgumentNullException("dllPath");
            }
            #endregion

            string errorLoadAssemblies = string.Empty;
            WFCompModel.Activity wfActivity = null;

            // Load all the assemblies from the DLL Path.
            errorLoadAssemblies = WorkflowComposer.LoadAssemblies(this.typeProvider, dllPath);

            if (!string.IsNullOrEmpty(errorLoadAssemblies))
            {
                TridentErrorHandler.ThrowTridentCustomException(
                    TridentErrorConstants.ErrorNumber6000004,
                    errorLoadAssemblies.ToString());
            }

            // Get the list of loaded Assemblies.
            Collection<Assembly> listAssm = WorkflowComposer.GetLoadedAssemblyList();

            wfActivity = actComposer.CreateCompModelActivity(wfModel.Root as CompositeActivityModel, listAssm);

            wfActivity.Description = wfModel.Description;

            // Update the Parameters
            actComposer.UpdateParameter(wfActivity, wfModel.Root, nullifyForCustomType);

            return wfActivity;
        }

        /// <summary>
        /// This is used to get all the loaded assembly List
        /// </summary>
        /// <returns></returns>
        private static Collection<Assembly> GetLoadedAssemblyList()
        {
            // Get the list of loaded Assemblies.
            Collection<Assembly> assemblyList = new Collection<Assembly>();
            Assembly[] asms;

            asms = AppDomain.CurrentDomain.GetAssemblies();
            foreach (Assembly asm in asms)
            {
                if (!assemblyList.Contains(asm))
                {
                    assemblyList.Add(asm);
                }
            }

            return assemblyList;
        }

        /// <summary>
        /// This function is used to create a temp save directory 
        /// and then download all the assemblies from registry into 
        /// the temp path.
        /// </summary>
        /// <param name="wfModel">Workflow model.</param>
        /// <param name="tempDir">The temp directory where the binaries have to be downloaded.</param>
        private void DownloadBinaries(TridentWorkflowModel wfModel, string tempDir)
        {
            #region Validation of Arguments
            if (wfModel == null)
            {
                throw new ArgumentNullException("wfModel");
            }
            #endregion

            try
            {
                BaseModel rootActModel = wfModel.Root;
                this.actComposer.DownloadLibraries(rootActModel, tempDir);
            }
            catch (TridentCustomException)
            {
                throw;
            }
            catch (Exception exp)
            {
                TridentErrorHandler.ProcessKnownExceptionsInBusinessLogic(exp);
                TridentErrorHandler.HandleAndThrowBusinessLogicException(
                    exp,
                    TridentErrorConstants.ErrorNumber6000021,
                    exp.Message);
            }
        }

        /// <summary>
        /// This function is used to create a temp save directory 
        /// and then download all the assemblies from registry into 
        /// the temp path.
        /// </summary>
        /// <param name="workflowActivity">Workflow for which the binaries have to be downloaded.</param>
        /// <param name="tempDir">The temp directory where the binaries have to be downloaded.</param>
        private static void DownloadBinaries(Activity workflowActivity, string tempDir)
        {
            #region Validation of Arguments
            if (workflowActivity == null)
            {
                throw new ArgumentNullException("workflowActivity");
            }
            #endregion

            try
            {
                // Download all the DLL's related to the blackbox activity properties.
                workflowActivity.DownloadBinaries(tempDir);
                ActivityComposer.DownloadWorkflowLibraries(workflowActivity.BaseSequence, tempDir);
            }
            catch (TridentCustomException)
            {
                throw;
            }
            catch (Exception exp)
            {
                TridentErrorHandler.ProcessKnownExceptionsInBusinessLogic(exp);
                TridentErrorHandler.HandleAndThrowBusinessLogicException(
                    exp,
                    TridentErrorConstants.ErrorNumber6000018,
                    exp.Message);
            }
        }

        /// <summary>
        /// Create the WFActivity from the path specified.
        /// </summary>
        /// <param name="localLocation">
        /// Local location where the assemblies are present.
        /// </param>
        /// <param name="xomlFilePath">
        /// The path of the xoml file.
        /// </param>
        /// <returns>
        /// The WFActivity.
        /// </returns>
        private WFActivity CreateWFActivity(Collection<FileReference> fileReferences)
        {
            WFActivity activity = null;

            // Load assemblies into appdomain and the typeprovider.
            string errors = LoadAssemblies(this.typeProvider, fileReferences);

            // Load the workflow.
            if (string.IsNullOrEmpty(errors))
            {
                FileReference xomlFile = fileReferences.FirstOrDefault(f => Helper.IsWorkflowFile(f.FilePath));

                if (xomlFile != null)
                {
                    using (XmlReader reader = new XmlTextReader(xomlFile.FilePath))
                    {
                        activity = this.LoadWorkflow(reader);
                    }
                }
            }
            else
            {
                TridentErrorHandler.ThrowTridentCustomException(TridentErrorConstants.ErrorNumber4000022, errors);
            }

            return activity;
        }

        /// <summary>
        /// Loads the assemblies from the folder specified.
        /// </summary>
        /// <param name="typeProvider">
        /// Type Provider into which the assemblies are to be loaded.
        /// </param>
        /// <param name="assemblyBase">
        /// The path of the assemblies' library.
        /// </param>
        /// <returns>
        /// Error string message.
        /// </returns>
        private static string LoadAssemblies(TypeProvider typeProvider, string assemblyBase)
        {
            #region Validation of Arguments
            if (typeProvider == null)
            {
                throw new ArgumentNullException("typeProvider");
            }

            if (string.IsNullOrEmpty(assemblyBase))
            {
                throw new ArgumentNullException("assemblyBase");
            }
            #endregion

            WorkflowComposer.ClearTypeProvider(typeProvider);

            // Clear the references.
            StringBuilder errorLoadAssemblies = new StringBuilder();
            typeProvider.AddAssembly(Assembly.GetExecutingAssembly());
            string[] assemblyFiles = Directory.GetFiles(assemblyBase, "*.dll");

            string error = WorkflowComposer.LoadAssemblies(typeProvider, assemblyFiles);
            if (!string.IsNullOrEmpty(error))
            {
                errorLoadAssemblies.AppendLine(error);
            }

            assemblyFiles = Directory.GetFiles(assemblyBase, "*.exe");

            error = WorkflowComposer.LoadAssemblies(typeProvider, assemblyFiles);
            if (!string.IsNullOrEmpty(error))
            {
                errorLoadAssemblies.AppendLine(error);
            }

            return errorLoadAssemblies.ToString();
        }

        /// <summary>
        /// Loads the assemblies from the folder specified.
        /// </summary>
        /// <param name="typeProvider">
        /// Type Provider into which the assemblies are to be loaded.
        /// </param>
        /// <param name="fileReferences">
        /// The file references to load.
        /// </param>
        /// <returns>
        /// Error string message.
        /// </returns>
        private static string LoadAssemblies(TypeProvider typeProvider, Collection<FileReference> fileReferences)
        {
            WorkflowComposer.ClearTypeProvider(typeProvider);
            typeProvider.AddAssembly(Assembly.GetExecutingAssembly());

            List<string> assemblyPaths = new List<string>();
            foreach (FileReference fileReference in fileReferences)
            {
                if (Helper.IsAssemblyFile(fileReference.FilePath))
                {
                    assemblyPaths.Add(fileReference.FilePath);
                }
            }
            return WorkflowComposer.LoadAssemblies(typeProvider, assemblyPaths.ToArray());
        }

        /// <summary>
        /// Loads the assemblies from the files specified.
        /// </summary>
        /// <param name="typeProvider">
        /// Type Provider into which the assemblies are to be loaded.
        /// </param>
        /// <param name="assemblyFiles">
        /// The files which has to be loaded.
        /// </param>
        /// <returns></returns>
        private static string LoadAssemblies(TypeProvider typeProvider, string[] assemblyFiles)
        {
            #region Validation of Arguments
            if (typeProvider == null)
            {
                throw new ArgumentNullException("typeProvider");
            }

            if (assemblyFiles == null)
            {
                throw new ArgumentNullException("assemblyFiles");
            }
            #endregion

            StringBuilder errorLoadAssemblies = new StringBuilder();
            foreach (string assemblyFile in assemblyFiles)
            {
                try
                {
                    bool isManaged = Helper.IsManagedAssembly(assemblyFile);
                    if (isManaged)
                    {
                        Assembly depAsm = null;
                        depAsm = AssemblyLoad.LoadFrom(assemblyFile);
                        if (!typeProvider.ReferencedAssemblies.Contains(depAsm))
                        {
                            typeProvider.AddAssembly(depAsm);
                        }
                    }
                }
                catch (ReflectionTypeLoadException rfNotFound)
                {
                    StringBuilder errorString = new StringBuilder();
                    foreach (Exception exp in rfNotFound.LoaderExceptions)
                    {
                        errorString.AppendLine(exp.Message);
                    }

                    Logger.Write(errorString.ToString());
                    errorLoadAssemblies.AppendLine(
                        TridentResourceManager.GetString("LoadAssemblyFailed",
                        assemblyFile,
                        errorString.ToString()));
                }
                catch (Exception exp)
                {
                    Logger.Write(exp.Message);
                    errorLoadAssemblies.AppendLine(
                        TridentResourceManager.GetString("LoadAssemblyFailed",
                        assemblyFile,
                        exp.Message));
                }
            }

            return errorLoadAssemblies.ToString();
        }

        /// <summary>
        /// This function is used to Load the WF from the XMLReader Passed in as Argument.
        /// </summary>
        /// <param workflowName="reader">XMLReader which contains the XOML of the WF.</param>
        /// <returns>ComponentModel.Activity instance of the Loaded WF.</returns>
        private WFActivity LoadWorkflow(XmlReader reader)
        {
            #region Validation of Arguments
            if (reader == null)
            {
                throw new ArgumentNullException("reader");
            }
            #endregion

            WFActivity rootActivity = null;
            ValidationErrorCollection errors = new ValidationErrorCollection();
            WorkflowMarkupSerializationManager serializationManager = null;

            // Define the DesignerSerializationManager based on the ServiceContainer.
            DesignerSerializationManager manager = new DesignerSerializationManager(serviceContainer);
            try
            {
                using (manager.CreateSession())
                {
                    // Defines the WorkflowMarkupSerializationManager which will be used to get 
                    // the WFAcitivty from XOML File.
                    serializationManager = new WorkflowMarkupSerializationManager(manager);

                    // Get the rootActivity of the XOML WF.
                    rootActivity =
                        new WorkflowMarkupSerializer().Deserialize(serializationManager, reader) as WFActivity;

                    // If there were errors while Deserializing the XOML file. 
                    // Then all the error will be put into a ValidationErrorCollection.
                    foreach (object deserializeError in manager.Errors)
                    {
                        if (deserializeError is WorkflowMarkupSerializationException)
                        {
                            errors.Add(new ValidationError(((WorkflowMarkupSerializationException)deserializeError).Message, 0x15b));
                        }
                        else
                        {
                            errors.Add(new ValidationError(deserializeError.ToString(), 0x15b));
                        }
                    }
                }
            }
            catch (Exception exception)
            {
                errors.Add(new ValidationError(exception.Message, 0x15b));
            }

            // If there are any errors while Deserializing. 
            // Throw WorkflowValidationFailedException with the ValidationErrorCollection as the argument.
            if (errors.HasErrors)
            {
                throw new WorkflowValidationFailedException(TridentResourceManager.GetString("LoadingWorkflowFailed"), errors);
            }

            return rootActivity;
        }

        /// <summary>
        /// This function is used to Save the Workflow into the XMLWriter.
        /// </summary>
        /// <param workflowName="writer">XMLWriter where the XOML has to be saved.</param>
        /// <param workflowName="rootActivity">RootActivity of the WF.</param>
        /// <returns>Whether Saved or Not.</returns>
        private bool SaveWorkflow(XmlWriter writer, WFActivity rootActivity)
        {
            #region Validation of Arguments
            if (writer == null)
            {
                throw new ArgumentNullException("writer");
            }

            if (rootActivity == null)
            {
                throw new ArgumentNullException("rootActivity");
            }
            #endregion

            ValidationErrorCollection errors = new ValidationErrorCollection();
            WorkflowMarkupSerializationManager serializationManager = null;

            // Define the DesignerSerializationManager based on the ServiceContainer.
            DesignerSerializationManager manager = new DesignerSerializationManager(serviceContainer);
            try
            {
                using (manager.CreateSession())
                {
                    // Defines the WorkflowMarkupSerializationManager which will be used to get 
                    // the WFAcitivty from XOML File.
                    serializationManager = new WorkflowMarkupSerializationManager(manager);

                    // This is used to Save the XOML into the XMLWriter.
                    new WorkflowMarkupSerializer().Serialize(serializationManager, writer, rootActivity);

                    // If there were errors while Serializing the XOML file. 
                    // Then all the error will be put into a ValidationErrorCollection.
                    foreach (object serializeError in manager.Errors)
                    {
                        if (serializeError is WorkflowMarkupSerializationException)
                        {
                            errors.Add(new ValidationError(((WorkflowMarkupSerializationException)serializeError).Message, 0x15b));
                        }
                        else
                        {
                            errors.Add(new ValidationError(serializeError.ToString(), 0x15b));
                        }
                    }
                }
            }
            catch (Exception exception)
            {
                errors.Add(new ValidationError(exception.Message, 0x15b));
            }

            // If there are any errors while Deserializing. 
            // Throw WorkflowValidationFailedException with the ValidationErrorCollection as the argument.
            if (errors.HasErrors)
            {
                throw new WorkflowValidationFailedException(
                    TridentResourceManager.GetString("SavingWorkflowFailed"),
                    errors);
            }

            return true;
        }

        /// <summary>
        /// Gets the Short Name of the property.
        /// </summary>
        /// <param name="name">name which contains the Full Name of the property.</param>
        /// <returns>Short name.</returns>
        private static string ShortName(string name)
        {
            int pos = name.LastIndexOf('.');
            if (pos > 0)
            {
                return name.Substring(pos + 1);
            }
            return name;
        }

        /// <summary>
        /// Import the file specified, into the temp directory.
        /// </summary>
        /// <param name="filePathStr">
        /// Path of the file to import.
        /// </param>
        /// <returns>
        /// Bool value indicating the status of the completed operation.
        /// </returns>
        private static bool DownloadFile(string filePathStr)
        {
            bool importDone = true;
            WebClient fileReader = new WebClient();

            try
            {
                Uri filePath = new Uri(filePathStr, UriKind.RelativeOrAbsolute);
                string tempAppFilePath = System.IO.Path.Combine(WorkflowComposer.TempImportedWorkflowDirectory.FullName, (filePath.Segments)[filePath.Segments.Length - 1]);
                fileReader.DownloadFile(filePath, tempAppFilePath);
            }
            catch (UriFormatException ex)
            {
                importDone = false;
                TridentErrorHandler.HandleAndThrowBusinessLogicException(ex, TridentErrorConstants.ErrorNumber4000017, ex.Message);
            }
            catch (IOException ex)
            {
                importDone = false;
                TridentErrorHandler.HandleAndThrowBusinessLogicException(ex, TridentErrorConstants.ErrorNumber4000018, ex.Message);
            }
            catch (ArgumentException ex)
            {
                importDone = false;
                TridentErrorHandler.HandleAndThrowBusinessLogicException(ex, TridentErrorConstants.ErrorNumber4000019, ex.Message);
            }
            catch (NotSupportedException ex)
            {
                importDone = false;
                TridentErrorHandler.HandleAndThrowBusinessLogicException(ex, TridentErrorConstants.ErrorNumber4000020, ex.Message);
            }
            catch (WebException ex)
            {
                importDone = false;
                TridentErrorHandler.HandleAndThrowBusinessLogicException(ex, TridentErrorConstants.ErrorNumber4000021, ex.Message);
            }
            finally
            {
                fileReader.Dispose();
            }

            return importDone;
        }

        /// <summary>
        /// Clear the updated activitylist.
        /// </summary>
        private void ClearUpdateStatus()
        {
            // Clear the updated activities before starting new import.
            updatedActivities.Clear();
        }

        /// <summary>
        /// This function is used to get the workflow defenition from Activity.
        /// </summary>
        /// <param name="rootAct">Root activity.</param>
        /// <returns>Workflow Defenition.</returns>
        private string GetWorkflowDefinition(WFActivity rootAct)
        {
            StringBuilder wfXoml = new StringBuilder();

            XmlWriter wfWriter = null;
            XmlWriterSettings wfWriterSetting = null;
            try
            {
                wfWriterSetting = new XmlWriterSettings();

                // This is used to Omit the XML Declaration.
                // this is not required when we are generatign XOML.
                wfWriterSetting.OmitXmlDeclaration = true;

                wfWriter = XmlWriter.Create(wfXoml, wfWriterSetting);
            }
            catch (Exception exp)
            {
                TridentErrorHandler.HandleAndThrowBusinessLogicException(
                       exp,
                       TridentErrorConstants.ErrorNumber4000025,
                       exp.Message);
            }

            // Validate the workflow.
            this.SaveWorkflow(wfWriter, rootAct);

            return wfXoml.ToString();
        }

        #region Create/Update Activity in Registry.

        #region From WorkflowModel.
        /// <summary>
        /// Create new workflow in Registry.
        /// </summary>
        /// <param workflowName="workflowName">Name of the Workflow.</param>
        /// <param workflowName="xomlContents">XOML Content of the Workflow.</param>
        /// <param workflowName="rootActivity">Root Activity of the workflow.</param>
        /// <param name="createNewActivities">Flag to create new activities. True only if importing.</param>
        /// <returns>eResearch.Acitivity of the Workflow created</returns>
        private Activity CreateWorkflow(
            TridentWorkflowModel wfModel,
            Collection<FileReference> openedReferences,
            string userName,
            bool openedFromFileSystem)
        {
            #region Validation of Arguments
            if (wfModel == null)
            {
                throw new ArgumentNullException("wfModel");
            }

            if (string.IsNullOrEmpty(userName))
            {
                throw new ArgumentNullException("userName");
            }
            #endregion

            Activity registryActivity = null;
            Dictionary<string, ActivitySequence> nameToSequenceMap = null;

            // Save the activity in registry.
            registryActivity = this.SaveERActivity(wfModel);

            if (TridentAuthentication.LoggedInUser != null)
            {
                registryActivity.Owner = TridentAuthentication.LoggedInUser;
            }
            else
            {
                User installingUser = User.Get("system", this.registryConnection);
                if (installingUser != null)
                {
                    registryActivity.Owner = installingUser;
                }
            }

            registryActivity.Save();

            // Create the Activity Sequence in registry.
            this.CreateActivitySequence(
                wfModel,
                registryActivity,
                openedReferences,
                ref nameToSequenceMap,
                openedFromFileSystem);

            registryActivity.ActivitySequences.Refresh();

            // Update Parameters in registry.
            #region Update Parameters
            string updateParamError = string.Empty;

            updateParamError = this.UpdateParameters(
                wfModel.Root,
                nameToSequenceMap);

            // Throw Exception if there is any error while updating the parameters.
            if (!string.IsNullOrEmpty(updateParamError))
            {
                StringBuilder errorStr = new StringBuilder();

                errorStr.AppendLine(TridentResourceManager.GetString("PropertyUpdateFailed"));
                errorStr.AppendLine(updateParamError);

                TridentErrorHandler.ThrowTridentCustomException(
                    TridentErrorConstants.ErrorNumber6000009,
                    errorStr.ToString());
            }
            #endregion

            this.AssignPackagesForProperties(wfModel, registryActivity, openedReferences);

            // Set the category of the workflow.
            this.SetNamespace(registryActivity, wfModel.Category.Id, userName);

            return registryActivity;
        }

        #region Activity Sequence

        /// <summary>
        /// This is used to create the Activity Sequence in registry.
        /// </summary>
        /// <param name="rootWorkflowModel">Workflow Model.</param>
        /// <param name="rootActivity">Er.Activity</param>
        /// <param name="nameToSequenceMap">Name to sequence map.</param>
        /// <param name="openedFromFileSystem">Set the flag if the Workflow is Opened from FileSystem</param>
        /// <returns>ActivitySequence.</returns>
        private ActivitySequence CreateActivitySequence(
            TridentWorkflowModel rootWorkflowModel,
            Activity rootActivity,
            Collection<FileReference> openedReferences,
            ref Dictionary<string, ActivitySequence> nameToSequenceMap,
            bool openedFromFileSystem)
        {
            ActivitySequence baseSequence = null;
            try
            {
                // Create the Base Activity Sequence.
                baseSequence = ActivitySequence.Create(null, rootActivity, registryConnection);

                // Set the name of the base sequence to the workflow name.
                baseSequence.Name = rootWorkflowModel.Name;

                // Set this activitysequence as the base of the workflow for base.
                baseSequence.IsBase = true;

                baseSequence.Save();

                nameToSequenceMap = new Dictionary<string, ActivitySequence>();

                // Create the ActivitySequence.
                this.CreateActivitySequence(rootWorkflowModel.Root, baseSequence, openedReferences, ref nameToSequenceMap, openedFromFileSystem);

                baseSequence.Save();
            }
            catch (TridentCustomException)
            {
                throw;
            }
            catch (Exception exp)
            {
                // Throw Create Activity Sequence Exception.
                TridentErrorHandler.HandleAndThrowBusinessLogicException(
                        exp,
                        TridentErrorConstants.ErrorNumber6000007,
                        TridentResourceManager.GetString("CreateActivitySequenceFailed"));
            }

            return baseSequence;
        }

        /// <summary>
        /// Creates the Activity Sequence of the ComponentModel.Activity.
        /// This Method is recursively called to generate all the activity Sequences.
        ///     This creats the activitySequence is in the registry.
        ///     
        /// This is also used to create/Import activity when in the import mode.
        /// </summary>
        /// <param name="activity">Activity model.</param>
        /// <param name="parent">Parent of the Activity.</param>
        /// <param name="nameToSequenceMap">Ref nametoSequenMap.</param>
        /// <returns>ActivitySequence.</returns>
        private ActivitySequence CreateActivitySequence(
            BaseModel model,
            ActivitySequence parentSeq,
            Collection<FileReference> openedReferences,
            ref Dictionary<string, ActivitySequence> nameToSequenceMap,
            bool openedFromFileSystem)
        {
            // Get trident activity from regitry.
            Activity regActivity = this.GetActivity(model);
            if (regActivity == null)
            {
                // In not in import mode we need to throw exception activity not found in registry. 
                TridentErrorHandler.ThrowTridentCustomException(
                    TridentErrorConstants.ErrorNumber4000023,
                    string.Format(CultureInfo.InvariantCulture, TridentResourceManager.GetString("ActivityNotFound"), model.Name));
            }

            // Create the Activity sequence in the registry based on the 
            ActivitySequence seq = ActivitySequence.Create(parentSeq, regActivity, registryConnection);

            // Set the activity sequence name with the unique name of the activity.
            seq.Name = model.UniqueId;

            // Save the sequence activity.
            seq.Save();

            // Update the name to sequence map.
            if (!nameToSequenceMap.ContainsKey(seq.Name))
            {
                nameToSequenceMap.Add(seq.Name, seq);
            }

            if (model.IsCompositeActivityModel || model.IsSubsectionModel || model.IsCompositeBlackBoxModel)
            {
                BaseCompositeModel compositeModel = model as BaseCompositeModel;
                for (int i = 0; i < compositeModel.Children.Count; i++)
                {
                    ActivitySequence childSequence = this.CreateActivitySequence(
                        compositeModel.Children[i],
                        seq,
                        openedReferences,
                        ref nameToSequenceMap, openedFromFileSystem);
                    childSequence.Position = i;
                    childSequence.Save();
                }
            }

            return seq;
        }

        #endregion

        #region Activity Parameter related functions

        /// <summary>
        /// This function is used to generate the Parameters and their assignments.
        /// </summary>
        /// <param name="regActivitySequence">ActivitySequence.</param>
        /// <param name="activity">ComponentModel.Activity.</param>
        /// <param name="nameToSequenceMap">List of nameToSequenceMap.</param>
        private string UpdateParameters(
            BaseModel rootActivityModel,
            Dictionary<string, ActivitySequence> nameToSequenceMap)
        {
            StringBuilder errorStr = new StringBuilder();
            try
            {
                ActivitySequence regActivitySequence = null;
                if (nameToSequenceMap.ContainsKey(rootActivityModel.UniqueId))
                {
                    regActivitySequence = nameToSequenceMap[rootActivityModel.UniqueId];
                }

                this.CreateParameters(rootActivityModel, nameToSequenceMap, regActivitySequence);

                // If the activity model is a composite activity model then iterate through and update the children's parameters.
                if (rootActivityModel.IsCompositeActivityModel || rootActivityModel.IsSubsectionModel || rootActivityModel.IsCompositeBlackBoxModel)
                {
                    BaseCompositeModel compositeActivityModel = rootActivityModel as BaseCompositeModel;
                    for (int i = 0; i < compositeActivityModel.Children.Count; i++)
                    {
                        string error = string.Empty;
                        error = this.UpdateParameters(
                            compositeActivityModel.Children[i],
                            nameToSequenceMap);

                        if (!string.IsNullOrEmpty(error))
                        {
                            errorStr.AppendLine(error);
                        }
                    }
                }
            }
            catch (Exception exp)
            {
                errorStr.Append(exp.Message);
            }
            return errorStr.ToString();
        }

        /// <summary>
        /// Creates the parameters.
        /// </summary>
        /// <param name="rootActivityModel">The root activity model.</param>
        /// <param name="nameToSequenceMap">The name to sequence map.</param>
        /// <param name="regActivitySequence">The reg activity sequence.</param>
        private void CreateParameters(
            BaseModel rootActivityModel,
            Dictionary<string, ActivitySequence> nameToSequenceMap,
            ActivitySequence regActivitySequence)
        {
            ParamModelKeyedCollection nameToParameterMap = null;

            regActivitySequence.Refresh();
            Activity regActivity = regActivitySequence.Activity;

            // Create the name to parameter Map.
            nameToParameterMap = WorkflowComposer.CreateNameToParameterMap(regActivity);

            foreach (ParameterDescriptionModel paramModel in rootActivityModel.InputParameters)
            {
                ActivityParameter regParam = null;
                string direction = paramModel.IsInputParameter ? WorkflowComposer.input : WorkflowComposer.output;
                if (nameToParameterMap.Contains(paramModel.PropertyName + "_" + direction))
                {
                    regParam = nameToParameterMap[paramModel.PropertyName + "_" + direction];
                    this.CreateParameterAssignment(regParam, regActivitySequence, paramModel, nameToSequenceMap);
                }
            }

            foreach (ParameterDescriptionModel paramModel in rootActivityModel.OutputParameters)
            {
                ActivityParameter regParam = null;
                string direction = paramModel.IsInputParameter ? WorkflowComposer.input : WorkflowComposer.output;
                if (nameToParameterMap.Contains(paramModel.PropertyName + "_" + direction))
                {
                    regParam = nameToParameterMap[paramModel.PropertyName + "_" + direction];
                    this.CreateParameterAssignment(regParam, regActivitySequence, paramModel, nameToSequenceMap);
                }
            }
        }

        /// <summary>
        /// Creates Parameter Assignment for the ActivityParameter in registry.
        /// </summary>
        /// <param name="regParam">Registry Parameter.</param>
        /// <param name="regActivitySequence">ActivitySequence which it is related to.</param>
        /// <param name="activity">ComponentModel.Activity.</param>
        /// <param name="nameToSequenceMap">List of nameToSequenceMap.</param>
        private ParameterAssignment CreateParameterAssignment(
            ActivityParameter regParam,
            ActivitySequence regActivitySequence,
            ParameterDescriptionModel paramModel,
            Dictionary<string, ActivitySequence> nameToSequenceMap)
        {
            ParameterAssignment regAssign = null;

            // Create the parameter assignment.
            regAssign = this.CreateParameterAssignment(regParam, regActivitySequence);

            // Update the parameter Assignment
            this.UpdateParameterAssignment(regAssign, paramModel, nameToSequenceMap);

            regAssign.Refresh();
            regActivitySequence.ParameterAssignments.Refresh();

            return regAssign;
        }

        /// <summary>
        /// This function is used to update the parameter assignments in the registry.
        ///     The parameter Assignment holds the value of the Param in the activity Sequence.
        /// </summary>
        /// <param name="regAssign">Parameter Assignment.</param>
        /// <param name="activity">CompnentModel.Activity.</param>
        /// <param name="nameToSequenceMap">List of nameToSequenceMap.</param>
        private void UpdateParameterAssignment(
            ParameterAssignment regAssign,
            ParameterDescriptionModel paramModel,
            Dictionary<string, ActivitySequence> nameToSequenceMap)
        {
            #region Declarations
            ActivityParameter regParam = null;
            ActivitySequence boundToSeq = null;
            ParameterAssignment boundTo = null;
            ParameterAssignment newBoundTo = null;
            Dictionary<string, ParameterAssignment> bindingAssignMap = null;
            ParamModelKeyedCollection nameToParameterMap = null;
            DatabindModel bindModel = null;
            #endregion

            // Get the activity parameter related to the Parameter which has to be updated.
            regParam = regAssign.ActivityParameter;

            regAssign.RequiredForWorkflow = paramModel.IsMandatoryForWorkflow;
            if (regParam.Direction == DirectionType.Input)
            {
                bool isBound = paramModel.IsDatabound;

                if (regAssign.IsBound)
                {
                    boundTo = regAssign.BoundTo;
                }

                if (isBound)
                {
                    bindModel = paramModel.Value as DatabindModel;
                    if (null != bindModel && nameToSequenceMap.ContainsKey(bindModel.SourceActivityName))
                    {
                        boundToSeq = nameToSequenceMap[bindModel.SourceActivityName];

                        boundToSeq.Refresh();
                        bindingAssignMap = WorkflowComposer.CreateNameToAssignmentMap(boundToSeq);

                        // The Path over is might be A.B.C => A is the activity unique name and B.C is the path.
                        // This stores ActivityParameter which is bound to.(i.e. B)
                        string boundParameter = bindModel.SourcePropertyName.Split(".".ToCharArray())[0];

                        string fullPathName = string.Format(CultureInfo.CurrentUICulture, "{0}.{1}",
                            bindModel.SourceActivityName,
                            boundParameter);

                        if (bindingAssignMap.ContainsKey(fullPathName))
                        {
                            newBoundTo = bindingAssignMap[fullPathName];
                        }
                        else
                        {
                            nameToParameterMap = WorkflowComposer.CreateNameToParameterMap(boundToSeq.Activity);


                            string direction = WorkflowComposer.output;
                            if (nameToParameterMap.Contains(boundParameter + "_" + direction))
                            {
                                newBoundTo = ParameterAssignment.Create(
                                    nameToParameterMap[boundParameter + "_" + direction],
                                    boundToSeq,
                                    registryConnection);
                                newBoundTo.Save();
                            }
                            else if (!boundToSeq.Activity.IsBlackbox)
                            {
                                TridentErrorHandler.ThrowTridentCustomException(
                                    TridentErrorConstants.ErrorNumber4000077,
                                    TridentResourceManager.GetString("OutputParameterNotFound",
                                        boundParameter,
                                        boundToSeq.Name));
                            }
                        }

                        if (newBoundTo != null)
                        {
                            if (!newBoundTo.Equals(boundTo))
                            {
                                regAssign.BoundTo = newBoundTo;
                            }
                            regAssign.BoundToPath = bindModel.SourcePropertyName;
                        }
                    }
                }
                else if (boundTo != null)
                {
                    // Unbind of the parameter binding is deleted.
                    regAssign.BoundTo = null;
                }
                else
                {
                    // Irrespective of whether the value is modified or null, 
                    // create parameter assignment entry as we need to store the isMandatory or not flag.
                    if (null == paramModel.Value)
                    {
                        regAssign.CurrentValue = null;
                    }
                    else
                    {
                        regAssign.CurrentValue = paramModel.Value.ToString();
                    }
                }
            }
            else
            {
                if (paramModel.IsMandatoryForWorkflow)
                {
                    // If the output label is empty, then we will be adding the name of the parameter as the output label.
                    regAssign.OutputLabel = (string.IsNullOrEmpty(paramModel.OutputLabel)) ? paramModel.Name : paramModel.OutputLabel;

                    regAssign.Type = paramModel.OutputType;
                    regAssign.IsFinal = paramModel.IsFinal;
                }
            }

            // Save to registry.
            regAssign.Save();
        }

        /// <summary>
        /// This function is used to create the parameter assignment in registry.
        /// </summary>
        /// <param name="regParam">Registry Parameter.</param>
        /// <param name="regActivitySequence">ActivitySequence which it is related to.</param>
        /// <returns></returns>
        private ParameterAssignment CreateParameterAssignment(
            ActivityParameter regParam,
            ActivitySequence regActivitySequence)
        {
            Dictionary<string, ParameterAssignment> bindingAssignMap = null;

            ParameterAssignment regAssign = null;
            try
            {
                regActivitySequence.Refresh();
                bindingAssignMap = WorkflowComposer.CreateNameToAssignmentMap(regActivitySequence);

                string key = string.Format(CultureInfo.CurrentUICulture, "{0}.{1}", regActivitySequence.Name, regParam.Name);
                if (bindingAssignMap.ContainsKey(key) && bindingAssignMap[key].ActivityParameter.Direction == regParam.Direction)
                {
                    regAssign = bindingAssignMap[key];
                }
                else
                {
                    // boundToPath is Null because you dont use it in this parameter assignment.
                    regAssign = ParameterAssignment.Create(regParam, regActivitySequence, this.registryConnection);
                    regAssign.Save();
                }
                // Not sure whether any Activity is using default Dataproducts. 
                // Need to uncomment the same when any one of the activity is using DefaultDataproducts.
                //if (regParam.DefaultToProduct)
                //{
                //    DataProduct dp = null;
                //    try
                //    {
                //        dp = DataProduct.Load(regParam.DefaultProductName, registryConnection);
                //    }
                //    catch (RecordNotFoundException)
                //    {
                //    }

                //    if (dp == null || !regParam.DefaultOverwrite)
                //    {
                //        dp = DataProduct.Create(regParam.DefaultProductName, regParam.DefaultProductType, registryConnection);
                //    }

                //    regAssign.BindToDataProduct = true;
                //    regAssign.Data = dp;
                //}

                //regAssign.Refresh();
            }
            catch (Exception exception)
            {
                TridentErrorHandler.HandleAndThrowBusinessLogicException(
                    exception,
                    TridentErrorConstants.ErrorNumber6000013,
                    exception.Message);
            }

            return regAssign;
        }

        #endregion

        /// <summary>
        /// Gets the Trident Activity from Registry for the activity model.
        /// </summary>
        /// <param name="activity">Activity model.</param>
        /// <returns>Trident activity.</returns>
        private Activity GetActivity(BaseModel activity)
        {
            Activity regActivity = null;

            try
            {
                if (!Guid.Empty.Equals(activity.Id))
                {
                    // This function would be called only from Open from registry and svae.
                    // So the model should obviously contain the ID. 
                    // If the ID is not present then there is some problem in the Model creation logic.
                    regActivity = Activity.Load(activity.Id, registryConnection);
                }
                // Search the updated activity list. Recently imported activities stored here. Used when save from file system and import.
                else if (updatedActivities.ContainsKey(activity.ActivityClass))
                {
                    regActivity = updatedActivities[activity.ActivityClass];
                }
                else
                {
                    regActivity = ER.Activity.CommonSearches.FindActivityInRegistry(activity.ActivityClass, this.registryConnection);
                }
            }
            catch (RecordNotFoundException exception)
            {
                TridentErrorHandler.HandleUIException(exception);
            }

            return regActivity;
        }

        /// <summary>
        /// This is use to Create/Update the Activity in Registry.
        /// </summary>
        /// <param name="workflowModel">Base workflow Model.</param>
        /// <returns>ER.Activity</returns>
        private Activity SaveERActivity(TridentWorkflowModel workflowModel)
        {
            Activity registryActivity = null;

            try
            {
                // Create a newer version of the workflow.
                if (null != workflowModel && !Guid.Empty.Equals(workflowModel.Id))
                {
                    // Load the workflow.
                    Activity oldVersion = Activity.Load(workflowModel.Id, this.registryConnection);

                    if (!oldVersion.IsLatestVersion())
                    {
                        TridentErrorHandler.ThrowTridentCustomException(TridentErrorConstants.ErrorNumber4000078,
                            TridentResourceManager.GetString("WorkflowNewerVersionExists"));
                    }

                    // Create a new version of the workflow.
                    registryActivity = oldVersion.CreateNewVersion(this.registryConnection);

                    // Update the name.
                    registryActivity.Name = workflowModel.Name;

                    // Set the label to empty.
                    registryActivity.VersionLabel = string.Empty;

                    registryActivity.Save();

                    //Inherit the ACL Info
                    Activity.InheritACLInfo(oldVersion, registryActivity, this.registryConnection);

                    // Create binding.
                    ActivityVersion versionBinding =
                        ActivityVersion.Create(oldVersion, registryActivity, VersionRelationshipType.Concrete, this.registryConnection);
                    oldVersion.NewerVersions.Add(versionBinding);

                    try
                    {
                        this.registryConnection.AutoSave = true;
                        registryActivity.Icon = workflowModel.WorkflowImage;
                    }
                    finally
                    {
                        this.registryConnection.AutoSave = false;
                    }
                }
                else
                {
                    // ActivityType.Root specifies that it is a workflow.
                    registryActivity = Activity.Create(
                        workflowModel.Name,
                        ActivityType.Root, TridentAuthentication.LoggedInUser,
                        registryConnection);
                    registryActivity.Save();
                }

                // Set the description.
                registryActivity.Description = workflowModel.Description;

                // Set whether blackbox or not.
                registryActivity.IsBlackbox = workflowModel.IsBlackBox;

                // Set whether Interactive or not.
                registryActivity.IsInteractive = workflowModel.IsInteractive;



                if (workflowModel.IsBlackBox)
                {
                    if (workflowModel.BlackBoxActivity != null)
                    {
                        // This might be the scenario where the workflow is opened from file system or 
                        //      The blackbox workflow is dragged and dropped.

                        // Remove the invalid bindings which are related to the blackbox activities.
                        workflowModel.ValidateBlackboxBindings();

                        registryActivity.XomlContents = this.GetWorkflowDefinition(workflowModel.BlackBoxActivity);
                    }
                    else
                    {
                        // workflowModel.BlackBoxActivity is null it specifies that the Workflow was opened from registry.
                        registryActivity.XomlContents = workflowModel.XomlContent;
                    }
                }

                // Save the workflow to registry.
                registryActivity.Save();
            }
            catch (RecordNotFoundException recordNotFound)
            {
                TridentErrorHandler.HandleAndThrowBusinessLogicException(
                    recordNotFound,
                   TridentErrorConstants.ErrorNumber6000006,
                   TridentResourceManager.GetString("WorkflowNotFound"));
            }
            catch (TridentCustomException)
            {
                throw;
            }
            catch (Exception exp)
            {
                TridentErrorHandler.HandleAndThrowBusinessLogicException(
                    exp,
                   TridentErrorConstants.ErrorNumber6000006,
                   TridentResourceManager.GetString("LoadingWorkflowFailed"));
            }

            return registryActivity;
        }
        #endregion

        #region From ComponentModel Activity.

        /// <summary>
        /// This function is used to create the activity in the registry
        /// from the component model activity.
        /// </summary>
        private Activity CreateWorkflowInRegistry(
            WFActivity rootActivity,
            WorkflowProperties properties,
            string userName,
            bool updateOnlyWorkflow,
            Collection<FileReference> references)
        {
            #region Validation of Arguments

            if (string.IsNullOrEmpty(properties.Name))
            {
                throw new ArgumentException("workflowName");
            }

            if (rootActivity == null)
            {
                throw new ArgumentNullException("rootActivity");
            }

            if (properties.CategoryId == null)
            {
                throw new ArgumentException("category");
            }

            #endregion

            Activity registryActivity = null;
            ActivitySequence seq = null;
            string updateParamError = string.Empty;
            Dictionary<string, ActivitySequence> nameToSequenceMap = null;

            FileReference workflowFile = references.FirstOrDefault(f => Helper.IsWorkflowFile(f.FilePath));
            if (workflowFile != null)
            {
                // If the workflow has been marked for update then create the new version of an existing workflow.
                if (workflowFile.UpdateExisting)
                {
                    Activity workflowToUpdate = Activity.Load(workflowFile.AssemblyInRegistryToUpdate.Id, this.registryConnection);
                    registryActivity = this.CreateRegistryActivityVersion(properties, rootActivity, workflowToUpdate);
                }
                else
                {
                    // Create a new workflow.
                    registryActivity = this.CreateRegistryActivity(properties, rootActivity);
                }
                // Create the base activity sequence.
                seq = this.CreateBaseSequence(properties.Name, registryActivity);

                nameToSequenceMap = new Dictionary<string, ActivitySequence>();

                // Create the ActivitySequence by recursing through the children.
                this.CreateActivitySequence(rootActivity, seq, 0, nameToSequenceMap, updateOnlyWorkflow, references);

                seq.Refresh();

                // Update Parameters
                #region Update Parameters
                updateParamError = this.UpdateParameters(seq.Children[0], rootActivity, nameToSequenceMap);

                // Throw Exception if there is any error while updating the parameters.
                if (!string.IsNullOrEmpty(updateParamError))
                {
                    StringBuilder errorStr = new StringBuilder();

                    errorStr.AppendLine(TridentResourceManager.GetString("PropertyUpdateFailed"));
                    errorStr.AppendLine(updateParamError);

                    TridentErrorHandler.ThrowTridentCustomException(
                        TridentErrorConstants.ErrorNumber6000009,
                        errorStr.ToString());
                }
                #endregion

                // Assign assembly packages which are associated with Blackbox activities.
                if (this.CheckIfBlackboxWorkflow(rootActivity))
                {
                    this.AssignAssemblyPackageForProperties(registryActivity, rootActivity, references);
                }

                // Set the category of the workflow.
                this.SetNamespace(registryActivity, properties.CategoryId, userName);
            }
            return registryActivity;
        }

        /// <summary>
        /// This function is used to generate the Parameters and their assignments.
        /// </summary>
        /// <param name="regActivitySequence">ActivitySequence.</param>
        /// <param name="activity">ComponentModel.Activity.</param>
        /// <param name="nameToSequenceMap">List of nameToSequenceMap.</param>
        private string UpdateParameters(
            ActivitySequence regActivitySequence,
            WFActivity activity,
            Dictionary<string, ActivitySequence> nameToSequenceMap)
        {
            StringBuilder errorStr = new StringBuilder();

            try
            {
                regActivitySequence.Refresh();

                // Get the registry activity.
                Activity regActivity = regActivitySequence.Activity;

                // For all the parameters of the activity assign values.
                foreach (ActivityParameter regParam in regActivity.ActivityParameters)
                {
                    // Retreive the dependency property.
                    WFCompModel.DependencyProperty depProp =
                        WFCompModel.DependencyProperty.FromName(WorkflowComposer.ShortName(regParam.Name), activity.GetType());

                    if (null != depProp)
                    {
                        this.CreateParameterAssignment(regParam, regActivitySequence, activity, nameToSequenceMap);
                    }
                    else
                    {
                        errorStr.AppendLine(string.Format(CultureInfo.CurrentUICulture, "'{0}' in Activity : '{1}'", regParam.Name, regActivity.Name));
                    }
                }

                // If the activity is a composite activity then recurse through the children.
                WFCompModel.CompositeActivity compositeActivity = activity as WFCompModel.CompositeActivity;
                if (compositeActivity != null)
                {
                    for (int i = 0; i < compositeActivity.Activities.Count; i++)
                    {
                        string error = string.Empty;

                        error = this.UpdateParameters(
                            regActivitySequence.Children[i],
                            compositeActivity.Activities[i],
                            nameToSequenceMap);

                        if (!string.IsNullOrEmpty(error))
                        {
                            errorStr.AppendLine(error);
                        }
                    }
                }
            }
            catch (Exception exp)
            {
                errorStr.Append(exp.Message);
            }

            return errorStr.ToString();
        }

        /// <summary>
        /// Create an registry activity and save it.
        /// </summary>
        /// <param name="workflowName">Name of the activity.</param>
        /// <param name="description">The description.</param>
        /// <param name="registryConnection">Current registry connection.</param>
        /// <returns>The created registry Activity.</returns>
        private ER.Activity CreateRegistryActivity(WorkflowProperties properties, WFActivity rootActivity)
        {
            ER.Activity registryActivity = null;
            try
            {
                User owner;
                if (this.ActComposer.IsInstallerInstance)
                {
                    owner = User.Load(Environment.UserName, this.registryConnection);
                }
                else
                {
                    owner = TridentAuthentication.LoggedInUser;
                }

                // ActivityType.Root specifies that it is a workflow.
                registryActivity = Activity.Create(properties.Name, ActivityType.Root, owner, this.registryConnection);

                // Set the Description of the Workflow.
                if (!string.IsNullOrEmpty(properties.Description))
                {
                    registryActivity.Description = properties.Description;
                }

                registryActivity.IsInteractive = properties.IsInteractive;
                registryActivity.IsBlackbox = this.CheckIfBlackboxWorkflow(rootActivity);
                registryActivity.XomlContents = this.GetWorkflowDefinition(rootActivity);

                // Save the registry Activity.
                registryActivity.Save();
            }
            catch (Exception exp)
            {
                TridentErrorHandler.HandleAndThrowBusinessLogicException(
                    exp,
                    TridentErrorConstants.ErrorNumber6000006,
                    TridentResourceManager.GetString("CreateWorkflowFailed"));
            }

            return registryActivity;
        }

        /// <summary>
        /// Crete a new version of the selected workflow.
        /// </summary>
        /// <param name="properties">The workflow details.</param>
        /// <param name="rootActivity">The component model workflow.</param>
        /// <param name="workflow">The workflow for which the newer version needs to be created.</param>
        /// <returns>The new version of the workflow.</returns>
        private ER.Activity CreateRegistryActivityVersion(WorkflowProperties properties, WFActivity rootActivity, ER.Activity workflow)
        {
            ER.Activity newVersion = null;
            try
            {
                if (!workflow.Security.Rights.AuthorWorkflow.Check(TridentAuthentication.LoggedInUser))
                {
                    TridentErrorHandler.ThrowTridentCustomException(TridentErrorConstants.ErrorNumber4000085,
                        TridentCommonResourceManager.GetString("WorkflowPermissionDenied"));
                }

                newVersion = workflow.CreateNewVersion(this.registryConnection);
                newVersion.Name = properties.Name;

                // Set the properties of the Workflow.
                if (!string.IsNullOrEmpty(properties.Description))
                {
                    newVersion.Description = properties.Description;
                }
                newVersion.IsInteractive = properties.IsInteractive;
                newVersion.IsBlackbox = this.CheckIfBlackboxWorkflow(rootActivity);
                newVersion.VersionLabel = string.Empty;
                newVersion.Save();

                //Inherit the ACL Info
                ER.Activity.InheritACLInfo(workflow, newVersion, this.registryConnection);

                // Create the bindings between versions.
                ActivityVersion versionBinding =
                    ActivityVersion.Create(workflow, newVersion, VersionRelationshipType.Concrete, this.registryConnection);
                workflow.NewerVersions.Add(versionBinding);

                try
                {
                    this.registryConnection.AutoSave = true;
                    newVersion.Icon = workflow.Icon;
                }
                finally
                {
                    this.registryConnection.AutoSave = false;
                }

            }
            catch (Exception exp)
            {
                TridentErrorHandler.HandleAndThrowBusinessLogicException(
                    exp,
                    TridentErrorConstants.ErrorNumber4000083,
                    TridentResourceManager.GetString("CreateWorkflowFailed"));
            }
            return newVersion;
        }

        /// <summary>
        /// Create a base sequence for the workflow.
        /// </summary>
        /// <param name="name">Name of the workflow</param>
        /// <param name="registryActivity">The registry activity created.</param>
        /// <returns>The base activity seqquence.</returns>
        private ActivitySequence CreateBaseSequence(string name, ER.Activity registryActivity)
        {
            ER.ActivitySequence baseSeq = null;

            try
            {
                // Create the Activity Sequence.
                baseSeq = ActivitySequence.Create(null, registryActivity, this.registryConnection);

                baseSeq.Name = name;

                // Set this activitysequence as the base of the workflow for base.
                baseSeq.IsBase = true;

                baseSeq.Save();
            }
            catch (Exception exp)
            {
                // Throw Create Activity Sequence Exception.
                TridentErrorHandler.HandleAndThrowBusinessLogicException(
                        exp,
                        TridentErrorConstants.ErrorNumber6000007,
                        TridentResourceManager.GetString("CreateActivitySequenceFailed"));
            }
            return baseSeq;
        }

        /// <summary>
        /// Creates the Activity Sequence of the ComponentModel.Activity.
        /// This Method is recursively called to generate all the activity Sequences.
        /// </summary>
        /// <param name="activity">ComponentModel Activity.</param>
        /// <param name="parent">Parent of the Activity.</param>
        /// <param name="position">Position of the activity in the sequence.</param>
        /// <param name="nameToSequenceMap">nametoSequenceMap.</param>
        /// <param name="updateOnlyWorkflow">True if only the workflow </param>
        /// <param name="references">The file references.</param>
        /// <returns>ActivitySequence.</returns>
        private ActivitySequence CreateActivitySequence(
            WFActivity activity,
            ActivitySequence parent,
            int position,
            Dictionary<string, ActivitySequence> nameToSequenceMap,
            bool updateOnlyWorkflow,
            Collection<FileReference> references)
        {
            ActivitySequence seq = null;
            try
            {
                // Retreive the activity if present in registry.
                Activity regActivity;
                if (updateOnlyWorkflow)
                {
                    // if the workflow is update only workflow, we need to get the activity instance from registry.
                    regActivity = Activity.CommonSearches.FindActivityInRegistry(activity.GetType().FullName, this.registryConnection);
                }
                else
                {
                    Type actType = activity.GetType();
                    if (updatedActivities.ContainsKey(actType.FullName))
                    {
                        // Retreive the activity if present in registry.
                        regActivity = updatedActivities[actType.FullName];
                    }
                    else
                    {
                        regActivity = ER.Activity.CommonSearches.FindActivityInRegistry(actType.FullName, this.registryConnection);
                        updatedActivities.Add(actType.FullName, regActivity);
                    }
                }

                if (regActivity == null)
                {
                    // In not in import mode we need to throw exception activity not found in registry. 
                    TridentErrorHandler.ThrowTridentCustomException(
                        TridentErrorConstants.ErrorNumber4000023,
                        string.Format(CultureInfo.CurrentUICulture, TridentResourceManager.GetString("ActivityNotFound"), activity.GetType().Name));
                }

                // Create a new activity sequence for the activity.
                seq = ActivitySequence.Create(parent, regActivity, registryConnection);

                seq.Name = activity.Name;
                seq.Position = position;

                // Save the sequence activity.
                seq.Save();

                // Add to the name-sequence dictionary.
                if (!nameToSequenceMap.ContainsKey(seq.Name))
                {
                    nameToSequenceMap.Add(seq.Name, seq);
                }

                // Recurse through the children if the current activity is composite.
                WFCompModel.CompositeActivity compositeActivity = activity as WFCompModel.CompositeActivity;
                if (compositeActivity != null)
                {
                    for (int i = 0; i < compositeActivity.Activities.Count; i++)
                    {
                        this.CreateActivitySequence(compositeActivity.Activities[i], seq, i, nameToSequenceMap, updateOnlyWorkflow, references);
                    }
                }

                parent.Refresh();
            }
            catch (Exception exp)
            {
                // Throw Update Activity Sequence Exception.
                TridentErrorHandler.HandleAndThrowBusinessLogicException(
                         exp,
                         TridentErrorConstants.ErrorNumber6000008,
                         TridentResourceManager.GetString("CreateActivitySequenceFailed"));
            }

            return seq;
        }

        /// <summary>
        /// Creates Parameter Assignment for the ActivityParameter in registry.
        /// </summary>
        /// <param name="regParam">Registry Parameter.</param>
        /// <param name="regActivitySequence">ActivitySequence which it is related to.</param>
        /// <param name="activity">ComponentModel.Activity.</param>
        /// <param name="nameToSequenceMap">List of nameToSequenceMap.</param>
        /// <returns>The parameter assignment created.</returns>
        private ParameterAssignment CreateParameterAssignment(
            ActivityParameter regParam,
            ActivitySequence regActivitySequence,
            WFActivity activity,
            Dictionary<string, ActivitySequence> nameToSequenceMap)
        {
            ParameterAssignment regAssign = CreateParameterAssignment(regParam, regActivitySequence);

            // Update the parameter assignment. Save is called within this.
            this.UpdateParameterAssignment(regAssign, activity, nameToSequenceMap);

            regActivitySequence.Refresh();

            return regAssign;
        }

        /// <summary>
        /// This function is used to update the parameter assignments in the registry.
        ///     The parameter Assignment holds the value of the Param in the activity Sequence.
        /// </summary>
        /// <param name="regAssign">Parameter Assignment.</param>
        /// <param name="activity">CompnentModel.Activity.</param>
        /// <param name="nameToSequenceMap">List of nameToSequenceMap.</param>
        private void UpdateParameterAssignment(
            ParameterAssignment regAssign,
            WFActivity activity,
            Dictionary<string, ActivitySequence> nameToSequenceMap)
        {
            ActivityParameter regParam = regAssign.ActivityParameter;

            WFCompModel.DependencyProperty depProp =
                WFCompModel.DependencyProperty.FromName(WorkflowComposer.ShortName(regParam.Name), activity.GetType());

            if (regParam.Direction == DirectionType.Input)
            {
                bool isBound = activity.IsBindingSet(depProp);

                ParameterAssignment boundTo = null;
                if (regAssign.IsBound)
                    boundTo = regAssign.BoundTo;

                if (isBound)
                {
                    WFCompModel.ActivityBind bind = activity.GetBinding(depProp);
                    ActivitySequence boundToSeq = nameToSequenceMap[bind.Name];

                    Dictionary<string, ParameterAssignment> bindingAssignMap = WorkflowComposer.CreateNameToAssignmentMap(boundToSeq);
                    ParameterAssignment newBoundTo = null;

                    // The Path over is might be A.B.C => A is the activity unique name and B.C is the path(bind.Path).
                    // This stores ActivityParameter which is bound to.(i.e. B)
                    string boundParameter = bind.Path.Split(".".ToCharArray())[0];

                    string fullPathName = string.Format(CultureInfo.CurrentUICulture, "{0}.{1}", bind.Name, boundParameter);
                    if (bindingAssignMap.ContainsKey(fullPathName))
                    {
                        newBoundTo = bindingAssignMap[fullPathName];
                    }
                    else
                    {
                        ParamModelKeyedCollection nameToParameterMap = WorkflowComposer.CreateNameToParameterMap(boundToSeq.Activity);

                        if (nameToParameterMap.Contains(boundParameter + "_" + WorkflowComposer.output))
                        {
                            newBoundTo = ParameterAssignment.Create(
                                nameToParameterMap[boundParameter + "_" + WorkflowComposer.output],
                                boundToSeq,
                                registryConnection);
                            newBoundTo.Save();
                        }
                        else if (!boundToSeq.Activity.IsBlackbox)
                        {
                            TridentErrorHandler.ThrowTridentCustomException(
                                TridentErrorConstants.ErrorNumber4000077,
                                TridentResourceManager.GetString("OutputParameterNotFound",
                                    boundParameter,
                                    boundToSeq.Activity.Name));
                        }
                    }

                    if (!newBoundTo.Equals(boundTo))
                    {
                        regAssign.BoundToPath = bind.Path;
                        regAssign.BoundTo = newBoundTo;
                    }
                }
                else if (boundTo != null)
                {
                    regAssign.BoundTo = null;
                }
                else
                {
                    object oldValue = null;
                    object defaultValue = null;
                    TypeConverter converter = TypeDescriptor.GetConverter(depProp.PropertyType);
                    if (converter.CanConvertFrom(typeof(string)) && (null != regParam.DefaultValue))
                    {
                        defaultValue = converter.ConvertFromString(regParam.DefaultValue);
                    }
                    if (regAssign.CurrentValue != null)
                    {
                        if (converter.CanConvertFrom(typeof(string)))
                            oldValue = converter.ConvertFromString(regAssign.CurrentValue);
                    }
                    else
                        oldValue = defaultValue;
                    object currentValue = activity.GetValue(depProp);
                    if (currentValue != null)
                    {
                        regAssign.CurrentValue = currentValue.ToString();
                    }
                    else if (oldValue != null)
                    {
                        regAssign.CurrentValue = oldValue.ToString();
                    }
                }

                regAssign.Save();
            }
        }
        #endregion

        #region blackboard methods

        /// <summary>
        /// Assign assembly packages to black box workflows based on properties of blacbox activities.
        /// </summary>
        /// <param name="registryWorkflow">The workflow object in registry.</param>
        /// <param name="rootActivity">The root component model activity.</param>
        private void AssignAssemblyPackageForProperties(Activity registryWorkflow, WFActivity rootActivity, Collection<FileReference> references)
        {
            try
            {
                Collection<AssemblyPackage> assemblyPackages = this.GetAssemblyPackagesForProperties(registryWorkflow, rootActivity, references);
                foreach (AssemblyPackage assemblyPackage in assemblyPackages)
                {
                    if (!ActivityComposer.IsAssemblyPackageAvailable(registryWorkflow.AssemblyPackages, assemblyPackage))
                    {
                        registryWorkflow.AssemblyPackages.Add(assemblyPackage);
                    }
                }

                //registryWorkflow.Save();

                registryWorkflow.AssemblyPackages.Refresh();
            }
            catch (Exception exp)
            {
                TridentErrorHandler.HandleAndThrowBusinessLogicException(
                    exp,
                    TridentErrorConstants.ErrorNumber6000017,
                    exp.Message);
            }
        }

        /// <summary>
        /// Retrieves all the assembly packages related to the blackbpz properties.
        /// </summary>
        /// <param name="registryWorkflow">>The workflow object in registry.</param>
        /// <param name="rootActivity">The root component model activity.</param>
        /// <returns>Assembly packages collection.</returns>
        private Collection<AssemblyPackage> GetAssemblyPackagesForProperties(
            Activity registryWorkflow,
            WFActivity rootActivity,
            Collection<FileReference> references)
        {
            Collection<AssemblyPackage> assemblyPackages = new Collection<AssemblyPackage>();
            string activityNamespace = rootActivity.GetType().Namespace;

            // If the activity is a component model activity then iterate through the properties to retrieve custom types.
            if (activityNamespace.Equals("System.Workflow.ComponentModel") || activityNamespace.Equals("System.Workflow.Activities"))
            {
                Collection<AssemblyPackage> assemblyPackageList = this.RetrievePackagesForProperties(rootActivity, references);
                foreach (AssemblyPackage assemblyPackage in assemblyPackageList)
                {
                    if (!ActivityComposer.IsAssemblyPackageAvailable(assemblyPackages, assemblyPackage))
                    {
                        assemblyPackages.Add(assemblyPackage);
                    }
                }
            }

            // If composite then recurse its children.
            WFCompModel.CompositeActivity compositeActivity = rootActivity as WFCompModel.CompositeActivity;
            if (compositeActivity != null)
            {
                foreach (WFActivity childActivity in compositeActivity.Activities)
                {
                    Collection<AssemblyPackage> childPackages = this.GetAssemblyPackagesForProperties(registryWorkflow, childActivity, references);
                    if (childPackages.Count > 0)
                    {
                        foreach (AssemblyPackage assemPkg in childPackages)
                        {
                            if (!ActivityComposer.IsAssemblyPackageAvailable(assemblyPackages, assemPkg))
                            {
                                assemblyPackages.Add(assemPkg);
                            }
                        }
                    }
                }
            }

            return assemblyPackages;
        }

        /// <summary>
        /// Get the custom types assigned as values to the activity properties if any. 
        /// </summary>
        /// <param name="activity">The activity whose properties need to be parsed.</param>
        private Collection<AssemblyPackage> RetrievePackagesForProperties(WFActivity activity, Collection<FileReference> references)
        {
            Collection<AssemblyPackage> assemblyPackageList = new Collection<AssemblyPackage>();
            PropertyInfo[] propertyList = activity.GetType().GetProperties();

            // Iterate through the properties and check if any of the properties contain any custom properties
            // and add them to packages.
            for (int iterator = 0; iterator < propertyList.Length; iterator++)
            {
                object valueObject = null;
                try
                {
                    valueObject = propertyList[iterator].GetValue(activity, null);
                }
                catch { continue; }

                if (valueObject != null)
                {
                    Assembly valueAssembly = valueObject.GetType().Assembly;
                    if (!valueAssembly.GlobalAssemblyCache)
                    {
                        // Get the Assembly package from registry.
                        Collection<AssemblyPackage> assemblyPackages = actComposer.GetAssemblyPackage(references, true);
                        foreach (AssemblyPackage assemblyPackage in assemblyPackages)
                        {
                            assemblyPackageList.Add(assemblyPackage);
                        }
                    }
                }
            }
            return assemblyPackageList;

        }

        /// <summary>
        /// Update the activity names in in the reference activity.
        /// </summary>
        /// <param name="rootActivity">The root activity.</param>
        /// <param name="nameMapping">The old name-new name mapping.</param>
        public static void UpdateActivityNames(WFActivity rootActivity, Hashtable nameMapping)
        {
            foreach (string oldName in nameMapping.Keys)
            {
                WFActivity activity = rootActivity.GetActivityByName(oldName);
                if (activity != null)
                {
                    activity.Name = nameMapping[oldName] as string;
                    UpdateActivityBindings(activity, nameMapping);
                }
            }
        }

        /// <summary>
        /// Update the bindings in the acitivity.
        /// </summary>
        /// <param name="activity">The activity to be updated.</param>
        /// <param name="nameMapping">The old name-new name mapping</param>
        private static void UpdateActivityBindings(WFActivity activity, Hashtable nameMapping)
        {
            Type activityType = activity.GetType();
            FieldInfo[] fieldInfoArray = activityType.GetFields(BindingFlags.Static | BindingFlags.Public);

            // Iterate through all the dependency properties and update their bindings.
            for (int iterator = 0; iterator < fieldInfoArray.Length; iterator++)
            {
                if (fieldInfoArray[iterator].FieldType == typeof(WFCompModel.DependencyProperty))
                {
                    WFCompModel.DependencyProperty depProp = fieldInfoArray[iterator].GetValue(activity) as WFCompModel.DependencyProperty;

                    if (depProp != null)
                    {
                        // If the binding is set then update the source of the binding.
                        if (activity.IsBindingSet(depProp))
                        {
                            WFCompModel.ActivityBind binding = activity.GetBinding(depProp);
                            if (nameMapping.ContainsKey(binding.Name))
                            {
                                binding.Name = nameMapping[binding.Name] as string;
                            }
                        }
                    }
                }
            }
        }

        /// <summary>
        /// Checks if the workflow activiy is a composite activity.
        /// </summary>
        /// <param name="activity">The workflow activity to be checked.</param>
        /// <returns>True if the activity is a blackbox activity.</returns>
        private bool CheckIfBlackboxWorkflow(WFActivity activity)
        {
            bool result = false;

            // Check if the activity is a blackbox activity.
            if (this.modelFactory.IsBlackBoxActivity(activity))
            {
                result = true;
            }
            else
            {
                // If the activity is a composite activity recurse its children.
                WFCompModel.CompositeActivity composite = activity as WFCompModel.CompositeActivity;
                if (composite != null)
                {
                    foreach (WFActivity child in composite.Activities)
                    {
                        if (CheckIfBlackboxWorkflow(child))
                        {
                            result = true;
                            break;
                        }
                    }
                }
            }
            return result;
        }
        #endregion


        /// <summary>
        /// Creates the Name to parameter Map of the activities.
        /// </summary>
        /// <param name="regActivity">Root Activity.</param>
        /// <returns>The list of NameToParameterMap.</returns>
        private static ParamModelKeyedCollection CreateNameToParameterMap(
            Activity regActivity)
        {
            ParamModelKeyedCollection nameToParameterMap = new ParamModelKeyedCollection();
            IEnumerable<ActivityParameter> activityParams = regActivity.ActivityParameters.Distinct();
            foreach (ActivityParameter item in activityParams)
            {
                nameToParameterMap.Add(item);
            }

            return nameToParameterMap;
        }

        /// <summary>
        /// Creates the Name to assignment Map.
        /// </summary>
        /// <param name="seq">AcitivtySequence.</param>
        /// <returns>List of NameToAssignmentMap.</returns>
        private static Dictionary<string, ParameterAssignment> CreateNameToAssignmentMap(
            ActivitySequence seq)
        {
            Dictionary<string, ParameterAssignment> nameToAssignmentMap = new Dictionary<string, ParameterAssignment>();
            IEnumerable<ParameterAssignment> paramAssigns = seq.ParameterAssignments.Where(item => item.ActivityParameter.Direction == DirectionType.Output);
            foreach (ParameterAssignment param in paramAssigns)
            {
                nameToAssignmentMap[string.Format(CultureInfo.CurrentUICulture, "{0}.{1}", param.Instance.Name, param.ActivityParameter.Name)] = param;
            }

            return nameToAssignmentMap;
        }

        /// <summary>
        /// Set the category for the activity.
        /// </summary>
        /// <param name="regActivity">The activity for which the category needs to be set.</param>
        /// <param name="categoryPath">The category path.</param>
        private void SetNamespace(ER.Activity regActivity, Guid category, string userName)
        {
            if (regActivity != null && regActivity.Namespaces != null)
            {
                regActivity.Namespaces.GetEnumerator();
                if (regActivity.Namespaces.Count > 0)
                {
                    regActivity.Namespaces.Clear();
                }
            }

            // Get the required category from registry.
            ER.Namespace requiredNamespace = null;
            if (category != Guid.Empty)
            {
                requiredNamespace = CategoriesComposer.GetWorkflowNamespaceById(category, this.registryConnection);
            }

            if (requiredNamespace == null)
            {
                // Save to uncategorized if category not found
                requiredNamespace = CategoriesComposer.GetUncategorizedWorkflowNamespace(this.registryConnection, userName);

                // Throw error if uncategorized not found.
                if (requiredNamespace == null)
                {
                    TridentErrorHandler.ThrowTridentCustomException(
                        TridentErrorConstants.ErrorNumber4000029,
                        TridentResourceManager.GetString("CategorySetError"));
                }
            }

            // Add the activity to the namespace.
            requiredNamespace.Activitys.Add(regActivity);

            regActivity.Namespaces.Refresh();
        }
        #endregion

        /// <summary>
        /// Open a blackbox workflow from the registry by creating a activity object from the xoml
        /// and converting it to workflow model.
        /// </summary>
        /// <param name="erActivity">The registry activity containing the workflow xoml.</param>
        /// <returns>The component model workflow.</returns>
        private WFActivity LoadBlackboxWorkflow(Activity erActivity)
        {
            string xomlContent = erActivity.XomlContents;
            if (string.IsNullOrEmpty(xomlContent))
            {
                TridentErrorHandler.ThrowTridentCustomException(TridentErrorConstants.ErrorNumber4000039,
                    TridentResourceManager.GetString("XomlContentNotFoundInRegistry"));
            }

            // Write the string to a memorystream temporarily so that it can be consumed by the deserializer.
            using (MemoryStream tempStream = new MemoryStream())
            {
                // Write the string to the memory stream.
                using (StreamWriter tempWriter = new StreamWriter(tempStream))
                {
                    tempWriter.Write(xomlContent);
                    tempWriter.Flush();

                    tempStream.Position = 0;

                    // Download the required binaries to the path.
                    string tempPath = WorkflowComposer.CreateTempDirectory();
                    WorkflowComposer.DownloadBinaries(erActivity, tempPath);

                    // Load the assemblies at the temp directory to the type provider.
                    string errors = WorkflowComposer.LoadAssemblies(this.typeProvider, tempPath);

                    if (string.IsNullOrEmpty(errors))
                    {
                        using (XmlReader reader = new XmlTextReader(tempStream))
                        {
                            // Deserialize the workflow.
                            WFActivity activity = this.LoadWorkflow(reader);

                            return activity;
                        }
                    }
                    else
                    {
                        TridentErrorHandler.ThrowTridentCustomException(TridentErrorConstants.ErrorNumber4000038, errors);
                    }
                }
            }
            return null;
        }

        /// <summary>
        /// Exports the workflow to package.
        /// </summary>
        /// <param name="workflow">The workflow.</param>
        /// <param name="connection">The connection.</param>
        private static void ExportWorkflowToPackage(Activity workflow, Connection source, Connection target)
        {
            try
            {
                workflow.ExportToPackage(source, target);
            }
            catch (Exception exp)
            {
                TridentErrorHandler.HandleAndThrowBusinessLogicException(
                   exp,
                   TridentErrorConstants.ErrorNumber1000000046,
                   exp.Message);
            }
        }

        /// <summary>
        /// Delete schedules of a workflow.
        /// </summary>
        /// <param name="registryActivity">The activity whose schedules need to be deleted.</param>
        private static void DeleteSchedulesOfWorkflow(Activity registryActivity)
        {
            // Retrieve the schedules and set the status to cancelled.
            var results = from activityInstance in registryActivity.Instances
                          from job in activityInstance.Jobs
                          from schedules in job.Schedules
                          select schedules;


            // Cancel the schedules associated with the node. The scheduler service cleans it.
            foreach (JobSchedule schedule in results)
            {
                schedule.Status = ScheduleStatus.Cancelled;
                schedule.Save();
            }
        }

        /// <summary>
        /// This function is used to check if the Assembly is a Custom Type Initializer or not?
        /// </summary>
        /// <param name="filePath">File path of the assembly.</param>
        /// <returns>Whether assembly implements custom type initializer or not.</returns>
        private static bool ContainsCustomType(string filePath)
        {
            bool isCustomType = false;
            if (Helper.IsManagedAssembly(filePath))
            {
                try
                {
                    // Find out if this file is an activity DLL or not.
                    Assembly assembly = AssemblyLoad.LoadFrom(filePath);
                    isCustomType = assembly.GetTypes().Any(type => type.IsSubclassOf(typeof(BaseTypeInitializer)));
                }
                catch (Exception)
                {
                    // Just log the error. This file will be marked as non-activity.
                    Logger.Write("ContainsCustomType(): Could not load assembly - " + filePath);
                }
            }

            return isCustomType;
        }

        #endregion

        #region IDisposable Members

        /// <summary>
        /// Dispose the disposable resources.
        /// </summary>
        public void Dispose()
        {
            this.Dispose(true);
            GC.SuppressFinalize(this);
        }

        /// <summary>
        /// Dispose the disposable resources.
        /// </summary>
        /// <param name="disposing">True if both native and managed resources are to be disposed. False for disposing only native resources</param>
        protected virtual void Dispose(bool disposing)
        {
            if (disposing)
            {
                if (this.typeProvider != null)
                {
                    this.typeProvider.Dispose();
                    this.typeProvider = null;
                }

                if (this.serviceContainer != null)
                {
                    this.serviceContainer.Dispose();
                    this.serviceContainer = null;
                }
            }
        }

        #endregion
    }
}
